Defines or declares a prototype for a user-defined function, or declares a Web service operation. The following syntax boxes describe the syntax for each use of the statement, beginning with a user-defined function definition.
FUNCTION function-name [ RETURNS ] return-type [ PRIVATE ] [ ( parameter[ , parameter ] ... ) ] : function-body |
Use the following syntax to declare a user-defined function prototype that is defined later in the same procedure or that is defined in another external procedure:
FUNCTION function-name [ RETURNS ] return-type [ ( parameter[ , parameter ] ... ) ] { FORWARD | [ MAP [ TO ] actual-name ] IN proc-handle | IN SUPER } . |
Use the following syntax to declare a Web service operation. For more information on declaring Web service operations, see OpenEdge Development: Web Services.
Indicates the data type of the function return value. You can specify return-type as one of the following data types. For more information on each data type, see the Data types reference entry:
{ CHARACTER | COM-HANDLE | DATE | DATETIME | DATETIME-TZ | DECIMAL | HANDLE | INT64 | INTEGER | LOGICAL | LONGCHAR | MEMPTR | RAW | RECID | ROWID | [ CLASS ] object-type-name } [ EXTENT [ constant ] ] |
If the specified class or interface type name conflicts with an abbreviation of a built-in primitive type name, such as INT for INTEGER, you must specify the CLASS keyword.
For a class or interface return value, ABL returns an object reference associated with the class or interface, not a class instance itself. For more information on object references, see the Class-based object reference reference entry.
An indeterminate array return value can be in one of two states: fixed or unfixed, meaning it either has a fixed dimension or it does not. An indeterminate array return value has an unfixed dimension when first defined. You can fix the dimension of an indeterminate array return value by:
Once fixed, ABL treats a fixed indeterminate array as a determinate array.
If you do not use the EXTENT option (or you specify constant as 0), the return value is not an array return value.
Indicates the following about the user-defined function:
Defines one or more parameters of the function.
For information on the parameter definition syntax, see the Parameter definition syntax reference entry.
The body of a function definition. Define function-body using the following syntax:
The logic of the function. This logic can contain the ABL statements allowed within a procedure block, except that the RETURN ERROR statement returns the Unknown value (?) for the function, regardless of its return type, but does not raise ERROR in the caller.
To return a function value of the data type specified by return-type, you can execute the RETURN statement to set a value of that data type to return at run time. If you omit the RETURN statement, the function returns the Unknown value (?), regardless of the data type specified by return-type.
If return-type is defined as a .NET array of mapped types (for example, "System.Byte[]"), you must return an object reference of the specified .NET array of mapped types in the RETURN statement. You cannot return an ABL array of a type that maps to the .NET array type (for example, INTEGER EXTENT) or the AVM raises a run-time error. If you do not execute any RETURN statement for return-type in the function-logic, the user-defined function returns the Unknown value (?) as its return value.
Each logic statement must end with a period.
Declares a prototype for a function in a procedure whose definition appears later in the same procedure. You must declare a user-defined function prototype when the function definition appears within the same procedure following the first use of the function. This prototype must appear in the procedure before the first use of the function.
The FUNCTION statement with the FORWARD option must include the following information on the function: the data type it returns, and the data type and mode (INPUT, OUTPUT, or INPUT-OUTPUT) of each parameter.
If you declare a function prototype, reference it, and do not define it before the end of the procedure, the compiler returns an error.
Declares prototype for a function that resides in a procedure external to the declaring procedure, with the following information:
A FUNCTION statement with the IN proc-handle option must include the following information on the function: the data type it returns, and the data type and mode (INPUT, OUTPUT, or INPUT-OUTPUT) of each parameter.
Declares a prototype for a function whose definition resides in a super procedure.
A FUNCTION statement with the IN SUPER option must include the following information on the function: the data type it returns, and the data type and mode (INPUT, OUTPUT, or INPUT-OUTPUT) of each parameter.
The first example, r-udf1.p, defines and references the user-defined function doubler( ), which accepts an integer and returns the integer multiplied by two:
r-udf1.p
/* r-udf1.p */ /* Defines and references a user-defined function */ /* Define doubler() */ FUNCTION doubler RETURNS INTEGER (INPUT parm1 AS INTEGER): RETURN (2 * parm1). END FUNCTION. /* Reference doubler() */ DISPLAY "doubler(0)=" doubler(0) SKIP "doubler(1)=" doubler(1) skip "doubler(2)=" doubler(2) skip. |
The second example, r-udf2.p, declares a prototype for, references, and defines doubler( ):
r-udf2.p
/* r-udf2.p */ /* Forward-declares, references, and defines a user-defined function */ /* Forward declare doubler() */ FUNCTION doubler RETURNS INTEGER (INPUT parm1 AS INTEGER) FORWARD. /* Reference doubler() */ DISPLAY "doubler(0)=" doubler(0). DISPLAY "doubler(1)=" doubler(1). DISPLAY "doubler(2)=" doubler(2). /* Define doubler() */ FUNCTION doubler RETURNS INTEGER (INPUT parm1 AS INTEGER): RETURN (2 * parm1). END FUNCTION. |
The third example consists of two procedures, r-udf3.p and r-udfdef.p. The example illustrates defining a prototype for user-defined function that is defined in an external procedure.
The procedure, r-udf3.p, declares the prototype for doubler( ), runs r-udfdef.p persistently, invokes doubler( ), and deletes the persistent procedure:
r-udf3.p
/* r-udf3.p */ /* References an externally-defined user-defined function */ /* Define items */ DEFINE VARIABLE myhand AS HANDLE NO-UNDO. DEFINE VARIABLE mystr AS CHARACTER NO-UNDO FORMAT "x(20)". /* Forward declare doubler() */ FUNCTION doubler RETURNS INTEGER (INPUT parm1 AS INTEGER) IN myhand. /* Run the procedure that defines doubler() */ RUN src\prodoc\langref\r-udfdef.p PERSISTENT SET myhand. /* Reference doubler() */ DISPLAY "doubler(0)=" doubler(0) SKIP "doubler(1)=" doubler(1) SKIP "doubler(17)=" doubler(17) SKIP. /* Delete the procedure that defines doubler */ DELETE PROCEDURE myhand. |
The second procedure, r-udfdef.p, defines doubler( ):
r-udfdef.p
/* r-udfdef.p */ /* Defines user-defined function doubler() */ FUNCTION doubler RETURNS INTEGER (INPUT parm1 AS INTEGER): RETURN (2 * parm1). END FUNCTION. |
To start the third example, run r-udf3.p in the Procedure Editor.
In the fourth example, r-fctrl2.p, the user-defined function fact( ) implements the factorial function, common in probability and statistics, and commonly notated "!" (6! = 6 x 5 x 4 x 3 x 2 x 1; 100! = 100 x 99 x 98 x ... x 3 x 2 x 1):
r-fctrl2.p
/* r-fctrl2.p */ /* Demonstrates user-defined function fact() */ DEFINE VARIABLE inp AS INTEGER LABEL "Input Value". FUNCTION fact RETURNS INTEGER (INPUT val AS INTEGER): IF val LT 0 THEN RETURN 0. IF val LE 1 THEN RETURN 1. RETURN val * fact(val - 1). END. REPEAT: UPDATE inp WITH TITLE "Factorials". DISPLAY fact(inp) LABEL "Factorial". END. |
When you invoke a user-defined function (or a built-in function), you do not need to assign the function's return value to a variable. That is, you can invoke a user-defined function as a statement, ignoring the return value. You might use this technique with a function that performs some action on a persistent object, such as a shared variable, when you want the action to occur and do not need to check the return value. For example:
When you invoke a user-defined function, you may pass a TABLE, TABLE-HANDLE, DATASET, or DATASET-HANDLE parameter by value, by reference, or by binding using the BY-VALUE, BY-REFERENCE, or BIND keyword, respectively. For example:
For more information about passing these parameters by value, by reference, or by binding, see the Parameter passing syntax reference entry.