Calling functions

Functions can be invoked, to execute the code they define.

A function can be invoked in different ways:
  1. with the CALL statement,
  2. in an expression, when the function returns a unique value,
  3. with a callback mechanism like WHENEVER ERROR CALL or the INITIALIZER attribute.
Note: The symbol used to identify the function to be called can be a static function name, or a variable referencing a function.

For basic data types such as INTEGER, arguments are passed by value (the value is copied on the stack) and records, while dynamic arrays and objects are passed by reference (a handle to the original data is copied on the stack and this allows modification of the original data inside the function).

In the following code example, the variable x defined in the MAIN block will not be modified by the function:

MAIN
  DEFINE x INTEGER
  LET x = 123
  CALL myfunc(x)
  DISPLAY x   -- displays 123
END MAIN

FUNCTION myfunc(x)
  DEFINE x INTEGER
  LET x = x + 1
END FUNCTION
When a function returns a single value, it can be invoked in an expression:
MAIN
    DISPLAY ( 500 + add(50,5) )
END MAIN

FUNCTION add(x,y) RETURNS INTEGER
    DEFINE x, y INTEGER
    RETURN (x + y)
END FUNCTION
The actual argument in a call to the function need not be of the declared data type of the formal argument. The runtime system will do the appropriate date type conversions. If data type conversion is not possible, a runtime error occurs. Note however that for historical reasons, Genero BDL data type conversion is quite permissive. The following example will not raise an error, because the string value is silently converted to a NULL INTEGER:
MAIN
    CALL add("aaaaa")
END MAIN

FUNCTION add(x)
    DEFINE x INTEGER
    DISPLAY "x = ", x
END FUNCTION
A function can invoke itself recursively:
MAIN
    CALL recursive(1)
END MAIN

FUNCTION recursive(x)
    DEFINE x INTEGER
    DISPLAY "x = ", x
    IF x<10 THEN
       CALL recursive(x+1)
    END IF
END FUNCTION
A function can be referenced by a variable, and be invoked through this variable in a CALL instruction, or in an expression:
TYPE t_func_ref FUNCTION (p1 INT, p2 INT) RETURNS INT
DEFINE fr t_func_ref
LET fr = FUNCTION add   -- Function with the same signature as t_func_ref
DISPLAY fr(100,200)