Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Functions

A function computes a result from its arguments and forgets everything else. Two calls with the same arguments give the same answer, as long as the function does not read a global variable.

FUNCTION Scale: DINT
    VAR_INPUT
        value: DINT;
        factor: DINT;
    END_VAR

    Scale := value * factor;
END_FUNCTION

The type after the colon is the result type. Inside the body, the name of the function is the result: you assign to it, and the last value you assigned is what the caller gets. A function without a result type returns nothing, and a call of it is a statement.

Nothing survives a call

Every local variable of a function is temporary, also in a VAR block:

FUNCTION Counter: DINT
    VAR
        n: DINT;
    END_VAR

    n := n + 1;
    Counter := n;
END_FUNCTION

Both calls of Counter() return 1. When you need the value of the previous call, use a function block.

A function may call itself. The compiler sets no limit on the depth, but the stack of the target does.

Parameters

Four blocks describe what goes in and what comes out:

FUNCTION Measure: DINT
    VAR_INPUT
        raw: INT;            (* a copy for the function *)
    END_VAR
    VAR_INPUT {ref}
        label: STRING;       (* the caller's text, not a copy *)
    END_VAR
    VAR_IN_OUT
        total: DINT;         (* read and written in the caller *)
    END_VAR
    VAR_OUTPUT
        valid: BOOL;         (* a second result *)
    END_VAR

    (* ... *)
END_FUNCTION

VAR_INPUT gives the function a copy, so a change inside the function stays inside it. This holds for large values as well: a string, an array, or a struct in VAR_INPUT is copied, and the caller does not see a write to it.

VAR_INPUT {ref} marks the whole block as “do not copy”. The function then works on the value of the caller, which is what a foreign function usually expects, and what you want for a large value that the function only reads.

VAR_IN_OUT is for data that the function reads and writes. It is always the caller’s variable.

VAR_OUTPUT carries a second result out of the call.

Calling

A call supplies every parameter, including the outputs. Either by position, in the order of the declaration, or by name:

r := Measure(raw, 'sensor', total, valid);
r := Measure(raw := raw, label := 'sensor', total := total, valid => valid);

:= gives a value to an input or to an in-out, => takes a value out of an output. A missing argument is an error, in both forms:

error[E032]: this POU takes 4 arguments but 2 arguments were supplied

An input with a default value (factor: DINT := 2;) is the exception: you can leave it out and get the default. This applies to the inputs at the end of the list only. When a parameter without a default comes after it, you must supply both. A call of a function block instance may leave out any parameter, because the instance keeps what the previous call gave it.

Arrays of any size

A function that works on an array of any length declares the parameter with * instead of a range, one * per dimension. LOWER_BOUND and UPPER_BOUND then give the bounds of the array that the caller passed:

FUNCTION Sum: DINT
    VAR_INPUT
        values: ARRAY[*] OF DINT;
    END_VAR
    VAR
        i: DINT;
    END_VAR

    FOR i := LOWER_BOUND(values, 1) TO UPPER_BOUND(values, 1) DO
        Sum := Sum + values[i];
    END_FOR
END_FUNCTION

The second argument of the two functions is the number of the dimension. They accept a parameter of this kind only, not an array of a fixed size. Such a parameter is always passed by reference, also in a VAR_INPUT block, and the compiler says so:

warning[E047]: Variable Length Arrays are always by-ref, even when declared in a by-value block

Results that are not a number

A result type can be a string, an array, or a struct:

FUNCTION Describe: STRING[20]
    VAR_INPUT
        code: DINT;
    END_VAR

    Describe := 'code ';
END_FUNCTION

The caller provides the memory for such a result. The compiler makes the result a hidden first parameter, a pointer to a variable of the caller, and the function writes the result through it.

What’s next

Functions forget. The next chapter is about the POUs that remember: function blocks and programs.