function-name |
(< [([prototype-clause]
[intermediate-result-clause])]
|
[parameter]
[,[parameter]]
... >) |
[array-index-expression] |
For an explanation of the symbols used in the syntax diagram, see Syntax Symbols.
Related Statements: DEFINE
PROTOTYPE
| DEFINE
FUNCTION
This document covers the following topics:
A function call invokes a Natural object of the type function.
A function is defined with the DEFINE FUNCTION
statement
which contains the parameters, local and application-independent variables, the
result value to be used and the statements to be executed when the function is
called.
A function is called by specifying either of the following:
the function name as defined in the DEFINE FUNCTION
statement,
or
an alphanumeric variable that contains the name of the function at
execution time. In this case, it is necessary to reference the variable in a
DEFINE PROTOTYPE
statement with the VARIABLE
keyword.
A function call can be used within a Natural statement instead of a read-only operand. In this case, the function has to return a result which is then processed by the statement like a field containing the same value.
It is also possible to use a function call in place of a Natural statement. In this case, the function need not return a result value; if returned, the value result is discarded.
Function calls are not allowed in the following situations:
in positions where the operand value is changed by the Natural statement, for example:
MOVE 1 TO #FCT(<..>)
;
in a DEFINE
DATA
statement;
in a database access statement, such as READ
,
FIND
,
SELECT
,
UPDATE
and
STORE
;
as an argument of Natural system functions, such as
AVER
,
SUM
and
*TRIM
;
in an array index expression;
as a parameter of a function call.
If a function call is used in an INPUT
statement, the return value
will be treated like a constant value. This leads to an automatic assignment of
the attribute
AD=O
to make this field write-protected (for output only).
Operand Definition Table:
Operand | Possible Structure | Possible Formats | Referencing Permitted | Dynamic Definition | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
function-name
|
S | A | A | U | yes | no |
Syntax Element Description:
Syntax Element | Description |
---|---|
function-name
|
Function Name:
|
prototype-clause |
Prototype Clause:
|
intermediate-result-clause |
Intermediate Result Clause:
|
parameter |
Parameter Specification:
See |
array-index-expression |
Array Index Notation:
If the result returned by the function call is an array, an index notation must be provided to address the demanded array occurrences. For details, refer to Index Notation in User-Defined Variables. |
PT=
prototype-name |
Natural requires parameter definitions and the function result to
resolve a function call at compile time. If no prototype matches
function-name
,
the parameters or the function result defined for the called function, you can
assign a matching prototype with the
prototype-clause
. In this case, the
referenced prototype steps in place and is used to resolve the parameter and
function result definitions. The function-name
declared in the referenced prototype is ignored.
Syntax Element Description:
Syntax Element | Description |
---|---|
prototype-name |
Prototype Name:
|
IR=
|
format-length [/array-definition] | ||||||||
[(array-definition)]
HANDLE OF OBJECT |
|||||||||
( | [/array-definition])
DYNAMIC
|
This clause can be used to specify the
format-length
/array
definition
of the result value for a function call if
neither the cataloged object of the function nor a prototype definition is
available. If a prototype is available for this function call or if a cataloged
object of the called function exists, the result value format specified with
the intermediate-result-clause
is
checked for data transfer compatibility.
Syntax Element Description:
Syntax Element | Description |
---|---|
format-length |
Format/Length Definition:
The format and length of the field. For information on the format/length definition of user-defined variables; see Format and Length of User-Defined Variables. |
array-definition |
Array Dimension Definition:
With an array-definition, you define the lower and upper bounds of the dimensions in an array definition. See Array Dimension Definition in the Statements documentation. |
HANDLE OF
OBJECT |
Handle of Object:
Used in conjunction with NaturalX. For further information, see NaturalX in the Programming Guide. |
A ,
B or U |
Data Format:
Possible formats are alphanumeric, binary or Unicode for dynamic variables. |
DYNAMIC |
Dynamic Variable:
A field can be defined as For further information on processing dynamic variables, see Introduction to Dynamic Variables and Fields. |
nX
|
|||||||||
|
|||||||||
operand |
( AD=
|
)
|
|||||||
You can specify single or multiple parameters to pass data values to the function. They
can be provided as constant values or variables, depending on the DEFINE DATA PARAMETER
definition
within the function.
The semantic and syntactic rules which apply to the function parameters are the same as
described in the parameters section of subprograms; see Parameters in
the description of the CALLNAT
statement.
Operand Definition Table:
Operand | Possible Structure | Possible Formats | Referencing Permitted | Dynamic Definition | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
operand
|
C | S | A | G | N * | A | N | P | I | F | B | D | T | L | C | G | O | yes | no |
Note:
The options marked with an asterisk only apply on Windows and Linux
platforms.
Syntax Element Description:
Syntax Element | Description | |
---|---|---|
nX
|
Parameters to be Skipped:
With the notation A parameter that is to be skipped must be defined with the keyword |
|
AD=
|
Attribute Definition:
If |
|
AD=O
|
Non-modifiable:
See session parameter Note: |
|
AD=M
|
Modifiable:
See session parameter This is the default setting. |
|
AD=A
|
Input only:
See session parameter |
|
Note: |
The example program FUNCEX01
uses the functions
F#ADDITION
,
F#CHAR
,
F#EVEN
and
F#TEXT
.
All example sources shown in this section are provided as source objects and cataloged objects in the Natural SYSEXPG system library.
** Example 'FUNCEX01': Function call (Program) ************************************************************************ DEFINE DATA LOCAL 1 #NUM (I2) INIT <5> 1 #A (I2) INIT <1> 1 #B (I2) INIT <2> 1 #C (I2) INIT <3> 1 #CHAR (A1) INIT <'A'> END-DEFINE * IF #NUM = F#ADDITION(<#A,#B,#C>) /* Function with three parameters. WRITE 'Sum of #A,#B,#C' #NUM ELSE IF #NUM = F#ADDITION(<1X,#B,#C>) /* Function with optional parameters. WRITE 'Sum of #B,#C' #NUM END-IF END-IF * DECIDE ON FIRST #CHAR VALUE F#CHAR (<>)(1) /* Function with result array. WRITE 'Character A found' VALUE F#CHAR (<>)(2) WRITE 'Character B found' NONE IGNORE END-DECIDE * IF F#EVEN(<#B>) /* Function with logical result value. WRITE #B 'is an even number' END-IF * F#TEXT(<'Hello', '*'>) /* Function used as a statement. * WRITE F#TEXT(<(IR=A12) 'Good'>) /* Function with intermediate result. * END
FUNCEX01
Sum of #B,#C 5 Character A found 2 is an even number *** Hello world *** Good morning
The function F#ADDITION
is defined in the example function
FUNCEX02
.
** Example 'FUNCEX02': Function call (Function) ************************************************************************ DEFINE FUNCTION F#ADDITION RETURNS (I2) DEFINE DATA PARAMETER 1 #PARM1 (I2) OPTIONAL 1 #PARM2 (I2) OPTIONAL 1 #PARM3 (I2) OPTIONAL END-DEFINE /* RESET F#ADDITION IF #PARM1 SPECIFIED F#ADDITION := F#ADDITION + #PARM1 END-IF IF #PARM2 SPECIFIED F#ADDITION := F#ADDITION + #PARM2 END-IF IF #PARM3 SPECIFIED F#ADDITION := F#ADDITION + #PARM3 END-IF /* END-FUNCTION * END
The function F#CHAR
is defined in the example function
FUNCEX03
.
** Example 'FUNCEX03': Function call (Function) ************************************************************************ DEFINE FUNCTION F#CHAR RETURNS (A1/1:2) /* F#CHAR(1) := 'A' F#CHAR(2) := 'B' /* END-FUNCTION * END
The function F#EVEN
is defined in the example function
FUNCEX04
.
** Example 'FUNCEX04': Function call (Function) ************************************************************************ DEFINE FUNCTION F#EVEN RETURNS (L) DEFINE DATA PARAMETER 1 #NUM (N4) BY VALUE LOCAL 1 #REST (I2) END-DEFINE /* DIVIDE 2 INTO #NUM REMAINDER #REST /* IF #REST = 0 F#EVEN := TRUE ELSE F#EVEN := FALSE END-IF /* END-FUNCTION * END
The function F#TEXT
is defined in the example function
FUNCEX05
in library SYSEXPG
.
** Example 'FUNCEX05': Function call (Function) ************************************************************************ DEFINE FUNCTION F#TEXT RETURNS (A20) BY VALUE DEFINE DATA PARAMETER 1 #TEXT1 (A5) BY VALUE 1 #TEXT2 (A1) BY VALUE OPTIONAL LOCAL 1 #FRAME (A3) END-DEFINE /* IF #TEXT2 SPECIFIED MOVE ALL #TEXT2 TO #FRAME /* COMPRESS #FRAME #TEXT1 'world' #FRAME INTO F#TEXT /* WRITE F#TEXT ELSE COMPRESS #TEXT1 'morning' INTO F#TEXT /* END-IF /* END-FUNCTION * END
According to the function definition, a function call may return a
single result field. This can be a scalar value or an array field, which is
processed like a temporary field in the statement where the function call is
embedded. If the result is an array, the function call must be immediately
followed by an array-index-expression
addressing the required occurrences.
For example, to access the first occurrence of the array returned:
#FCT(<#A,#B>)(1)
In order to properly resolve a function call at compile time, the compiler requires the format, length and array structure of the parameters and the function result. The parameters specified in the function call are checked against the corresponding definitions in the function to ensure that they match. If a function is used within a statement instead of an operand, the function result must match the format, length and array structure of the operand.
You have three options to provide this information:
Retrieve the parameter and result specifications implicitly from the
cataloged object (if available) of the called function if no
DEFINE PROTOTYPE
statement is executed earlier.
This method requires the least amount of programming effort.
Use a DEFINE
PROTOTYPE
statement. You have to use a DEFINE
PROTOTYPE
statement if the cataloged object of the called function is
not available or if the function name is not known at compile time, that is,
instead of a function name the name of an alphanumeric variable is specified in
the function call.
Specify an explicit
(IR=
)
clause in the function call.
The first two methods comprise a full validation of the format, length and array structure of the parameters and the function result.
If neither a DEFINE PROTOTYPE
statement nor a cataloged
function object exists, you can use the following clauses in your function
call:
The (IR=
)
clause specifies the function result format/length/array structure.
This clause determines which format/length/array structure the
compiler should assume for the result field (the intermediate result as used by
the statement that contains the function call). If a prototype definition is
available for a function call, the (IR=
) clause overrules the
specifications in the prototype.
The (IR=
) clause does not enforce any parameter
checks.
The (PT=
) clause uses
a previously defined prototype with a name other than the function name. This
clause validates the parameters and the function result by using a DEFINE
PROTOTYPE
statement with the referenced name.
In the following example, the function #MULT
is called,
but the parameter and result specifications from the prototype whose name is
#ADD
apply:
#I := #MULT(<(PT=#ADD) 2 , 3>)
The first of the following definitions found is used to check the specified parameters:
the prototype definition referenced in the
(PT=)
clause;
the prototype definition in the DEFINE PROTOTYPE
statement
where the prototype name matches the function name used in the function
call;
the parameter specifications in the cataloged function object which
are supplied with the DEFINE FUNCTION
statement.
If none of the above is specified, no parameter validation is performed. This provides you the option to supply any number and layout of parameters in the function call without receiving a syntax error.
The first of the following definitions found is used to check the function result:
the definition provided in the
(IR=
)
clause;
the
RETURNS
definition in the prototype referenced in the
(PT=)
clause;
the prototype definition in the DEFINE PROTOTYPE
statement where the prototype name matches the function name used in the
function call;
the function result specification in the cataloged function object.
If none of the above is specified, a syntax error occurs.
Program:
** Example 'FUNCBX01': Declare result value and parameters (Program) ************************************************************************ * DEFINE DATA LOCAL 1 #PROTO-NAME (A20) 1 #PARM1 (I4) 1 #PARM2 (I4) END-DEFINE * DEFINE PROTOTYPE VARIABLE #PROTO-NAME RETURNS (I4) DEFINE DATA PARAMETER 1 #P1 (I4) BY VALUE OPTIONAL 1 #P2 (I4) BY VALUE END-DEFINE END-PROTOTYPE * #PROTO-NAME := 'F#MULTI' #PARM1 := 3 #PARM2 := 5 * WRITE #PROTO-NAME(<#PARM1, #PARM2>) WRITE #PROTO-NAME(<1X ,5>) * WRITE F#MULTI(<(PT=#PROTO-NAME) #PARM1,#PARM2>) * WRITE F#MULTI(<(IR=N20) #PARM1, #PARM2>) * END
Function F#MULTI
:
** Example 'FUNCBX02': Declare result value and parameters (Function) ************************************************************************ DEFINE FUNCTION F#MULTI RETURNS #RESULT (I4) BY VALUE DEFINE DATA PARAMETER 1 #FACTOR1 (I4) BY VALUE OPTIONAL 1 #FACTOR2 (I4) BY VALUE END-DEFINE /* IF #FACTOR1 SPECIFIED #RESULT := #FACTOR1 * #FACTOR2 ELSE #RESULT := #FACTOR2 * 10 END-IF /* END-FUNCTION * END
All function calls used within a Natural statement are evaluated before the statement execution starts. They are evaluated in the same order in which they appear in the statement. Function result values are stored in temporary fields that are later used as operands for execution of the statement.
Calling a function that has modifiable parameters which are repeatedly used within the same statement can cause different function results as indicated in the following example.
Before the COMPUTE
statement is started, variable
#I
has the value 1
. In a first step, function
F#RETURN
is executed. This changes the value of #I
to
2
and returns a value of 2
as the function result.
After this, the COMPUTE
operation starts and sums up the values of
#I (2)
and the temporary field (2)
to a value of
4
.
** Example 'FUNCCX01': Parameter changed within function (Program) ************************************************************************ DEFINE DATA LOCAL 1 #I (I2) INIT <1> 1 #RESULT (I2) END-DEFINE * COMPUTE #RESULT := #I + F#RETURN(<#I>) /* First evaluate function call, /* then execute the addition. * WRITE '#I :' #I / '#RESULT:' #RESULT * END
** Example 'FUNCCX02': Parameter changed within function (Function) ************************************************************************ DEFINE FUNCTION F#RETURN RETURNS #RESULT (I2) BY VALUE DEFINE DATA PARAMETER 1 #PARM1 (I2) BY VALUE RESULT END-DEFINE /* #PARM1 := #PARM1 + 1 /* Increment parameter. #RESULT := #PARM1 /* Set result value. /* END-FUNCTION * END
FUNCCX01
:
#I : 2 #RESULT: 4
You can also use a function call in place of a Natural statement without embedding the function call in a statement. In this case, the function call need not return a result value; if returned, the result value is discarded.
You can avoid that such a function call is considered to be part of a
previous statement by separating the function call from the previous statement
with a semicolon (;
) as shown in the following example.
Program:
** Example 'FUNCDX01': Using a function as a statement (Program) ************************************************************************ DEFINE DATA LOCAL 1 #A (I4) INIT <1> 1 #B (I4) INIT <2> END-DEFINE * * WRITE 'Write:' #A #B F#PRINT-ADD(< 2,3 >) /* Function call belongs to operand list /* immediately preceding it. * WRITE // '*************************' // * WRITE 'Write:' #A #B; /* Semicolon separates operands and function. F#PRINT-ADD(< 2,3 >) /* Function call does not belong to the /* operand list. * END
Function:
** Example 'FUNCDX02': Using a function as a statement (Function) ************************************************************************ DEFINE FUNCTION F#PRINT-ADD RETURNS (I4) DEFINE DATA PARAMETER 1 #SUMMAND1 (I4) BY VALUE 1 #SUMMAND2 (I4) BY VALUE END-DEFINE /* F#PRINT-ADD := #SUMMAND1 + #SUMMAND2 /* Result of function call. WRITE 'Function call:' F#PRINT-ADD /* END-FUNCTION * END
Output of Program FUNCDX01
:
Function call: 5 Write: 1 2 5 ************************* Write: 1 2 Function call: 5