Release 10.1A: OpenEdge Development:
Progress 4GL Reference

> ## FUNCTION statement

> Defines or forward declares a user-defined function.

> You can also use the FUNCTION statement to invoke a Web service operation. For more information on invoking Web service operations, see OpenEdge Development: Web Services .

> #### Syntax

>     FUNCTION function-name [ RETURNS ] data-type [ PRIVATE ]
>       [ ( parameter [, parameter ] ... ) ]
>       {     FORWARD
>          |  [ MAP [ TO ] actual-name ] IN proc-handle
>          |  IN SUPER
>       }

> Use the following syntax to invoke a Web service operation:

>     FUNCTION operationName [ RETURNS ] data-type
>       [ ( parameter [ , parameter ] ... ) ]
>       IN hPortType .

> ``function-name``

> The name of the function. You must avoid Progress reserved keywords. For a list of Progress keywords, see the Keyword Index in this manual.

> `[ RETURNS ] `data-type``

> Indicates the function returns a value, and specifies the data type of that return value. Progress provides the following return value data types: CHARACTER, CLASS, COM-HANDLE, DATE, DATETIME, DATETIME-TZ, DECIMAL, HANDLE, INTEGER, LOGICAL, LONGCHAR, MEMPTR, RAW, RECID, ROWID, and WIDGET-HANDLE.

> You specify a class or interface as a return value for a user-defined function using the following syntax:

>     [ CLASS ] { type-name }

> Progress passes the object reference associated with the class or interface (by value), not the class or interface itself.

> ``type-name``

> A character string that specifies the type name of the class or interface. Specify a type name using the `package`.`class-name` syntax as described in the Type-name syntax reference entry in this book.

> If the specified class or interface type name conflicts with an abbreviation of a built-in Progress data type name, such as INT for INTEGER, you must specify the CLASS keyword.

> Note: If you invoke a function on an AppServer, the function cannot return a value as a LONGCHAR, MEMPTR, or CLASS.

> `PRIVATE`

> Indicates the following about the user-defined function:

> - That it cannot be invoked from an external procedure-that is, from a procedure file external to the current procedure file.
> - That the INTERNAL-ENTRIES attribute on the procedure that defines it does not provide its name (unless the procedure that defines it is the current procedure file).
> - That the GET-SIGNATURE method on the procedure that defines it does not provide its signature (unless the procedure that defines it is the current procedure file).
> `( `parameter` [, `parameter` ] ... )`

> Defines one or more parameters of the function.

> For the parameter definition syntax, see the Parameter definition syntax reference entry in this book.

> `FORWARD`

> Lets a procedure reference a user-defined function whose definition has not yet appeared. You must use this option when the definition of the function appears later in the procedure.

> 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.

> This entry uses the term forward declaration to refer to statements such as the FUNCTION statement with the FORWARD option. This entry also mentions forward declaring user-defined functions.

> If you forward declare a user-defined function, reference it, and do not define it before the end of the procedure, the compiler reports an error.

> `IN `proc-handle``

> Indicates that the function’s definition resides in another procedure. The `proc-handle` parameter represents an expression that evaluates to a handle to the procedure that defines the function. This procedure can be an active procedure in the local context or a remote persistent procedure. For more information on remote user-defined functions, see OpenEdge Application Server: Developing AppServer Applications .

> The FUNCTION statement with the IN 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.

> `[ MAP [ TO ] `actual-name` ] IN `proc-handle``

> Indicates three things: that `function-name` (the second element in the FUNCTION statement) is an alias (alternative name) of the function, that `actual-name` is the name that appears in the definition of the function, and that the definition of the function resides in another procedure.`actual-name` represents the actual name of the function. `proc-handle` represents an expression that evaluates to a handle to the procedure that defines the function.

> Note: The MAP option might simplify your code if it references two different user-defined functions that have the same name but that reside in different procedures.

> `IN SUPER`

> Indicates that the implementation of the function resides in a super procedure. For more information on super procedures, see OpenEdge Development: Progress 4GL Handbook .

> ``operationName``

> The name of a Web service operation specified in a WSDL file.

> ``hPortType``

> A handle to a procedure object that encapsulates a Web service operation.

> Examples

> 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`, forward declares, 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.
>         RETURN (2 * parm1).
>         END FUNCTION.

> The third example consists of two procedures, `r-udf3.p` and `r-udfdef.p`. The example illustrates defining a user-defined function in an external procedure.

> The first procedure, `r-udf3.p`, runs the first procedure persistently, declares doubler(), references it, 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.
>     DEFINE VARIABLE mystr  AS CHARACTER 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; 100! = 100 x 99 x 98 x ... x 2)`.

> r-fctrl2.p
>     /* r-fctrl2.p */
>     /* demonstrates user-defined function fact() */

>     FUNCTION fact RETURNS INTEGER (val AS INTEGER):
>       IF val LT 0 THEN RETURN 0.
>       IF val LE 1 THEN RETURN 1.
>       RETURN val * fact(val - 1).
>     END.

>     DEFINE VARIABLE inp AS INTEGER LABEL "Input Value".
>     REPEAT:
>       UPDATE inp WITH TITLE "Factorials".
>       DISPLAY fact(inp) LABEL "Factorial".
>     END.

> #### Notes

> - Before you reference a user-defined function, you must forward declare it, declare it external (by using FUNCTION statement’s IN option), or define it.

> - To declare a function forward or external, you must specify at minimum the function name and return type, and for each parameter, the mode and data type.

> - To define a function you have forward declared, you must specify at minimum the function name, the return type, the parameters (if any), and the logic.

> - A period must appear after the FUNCTION statement and after each logic statement.

> - A user-defined function’s logic must not reference, either directly or indirectly, statements that block I/O (namely, the CHOOSE, INSERT, PROMPT-FOR, READKEY, SET, UPDATE, and WAIT-FOR statements).

> - You cannot define shared objects, work tables, temporary tables, or ProDataSet objects within a user-defined function.

> - Progress implements scalar and array parameters of user-defined functions as NO-UNDO variables.

> - A reference to a user-defined function must match the forward declaration or definition with respect to the return type, and with respect to the number, type, and mode of the parameters.

> - When a Progress 4GL predicate (such as a WHERE clause) contains a user-defined function, Progress evaluates the function once-when it opens the query or enters the FOR EACH block.

> - When Progress encounters a user-defined function declared external that references a user-defined function declared external that references a user-defined function declared external, etc., Progress tolerates up to 64 levels of indirection. At the 65th level, Progress issues an error message and returns the Unknown value (`?`).

> - If a user-defined function has one or more buffer parameters and its definition resides in another procedure, the referencing procedure and the defining procedure must reside on the same machine. If a user-defined function does not have buffer parameters, the invoking procedure and the defining procedure can reside on different machines.

> - When you invoke a user-defined function (or a built-in function), you need not assign the function’s return value to a variable. 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 want to check the return value. For example:

>     doubler(my-shared-variable).

> - 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:

>     myfunc(OUTPUT TABLE tt BY-REFERENCE).

> For more information about passing these parameters by value, by reference, or by binding, see the Parameter passing syntax reference entry in this book.

> #### See also

> COMPILE statement, DYNAMIC-FUNCTION function, GET-SIGNATURE( ) method, INTERNAL-ENTRIES attribute, Parameter definition syntax, PROGRAM-NAME function, RETURN statement

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095