FUNCTION
Declare a user-defined function name and formal parameters
Syntax
[STATIC] FUNCTION <idFunction>[(<idParam list>)] [LOCAL <identifier> [[:= <initializer>], ... ]] [STATIC <identifier> [[:= <initializer>], ... ]] [FIELD <identifier list> [IN <idAlias>]] [MEMVAR <identifier list>] . . <executable statements> . RETURN <exp>
Arguments
<idFunction> is the name of the user-defined function to be declared. User-defined function names can be any length, but only the first 10 characters are significant. Names can contain any combination of characters, numbers, or underscores, but must begin with a character or an underscore. Leading underscores are not recommended since they are reserved for internal functions.
<idParam list> is the declaration of one or more parameter variables. Variables specified in this list are declared local.
STATIC FUNCTION declares a user-defined function that can be invoked only by procedures and user-defined functions declared in the same program (.prg) file.
LOCAL declares and optionally initializes a list of variables or arrays whose visibility and lifetime is the current function.
STATIC declares and optionally initializes a list of variables or arrays whose visibility is the current user-defined function and lifetime is the duration of the program.
FIELD declares a list of identifiers to use as field names whenever encountered. If the IN clause is specified, referring to the declared name includes an implicit reference to the specified alias.
MEMVAR declares a list of identifiers to use as private or public memory variables or arrays whenever encountered.
<identifier> and <identifier list> are labels to be used as variable or array names.
<initializer> is a value to which an array or variable is originally set in an inline expression. RETURN <exp> passes control back to the calling procedure or user-defined function, returning the result of <exp> as the value of the function. Each function must have at least one
RETURN statement that returns a value. RETURN statements can occur anywhere in the body of a function.
Description
The FUNCTION statement declares a user-defined function and an optional list of local variables to receive parameters often referred to as formal parameters. A user-defined function is a subprogram comprised of a set of declarations and statements executed whenever you refer to <idFunction> followed by an open and closed parentheses pair. A function definition begins with a FUNCTION statement which is the FUNCTION declaration and ends with the next FUNCTION statement, PROCEDURE statement, or end of file.
Functions encapsulate a computational block of code and then later create expressions using the value returned. Functions and procedures increase both readability and modularity, isolate change, and help manage complexity.
A function in Harbour is the same as a procedure, except that it must return a value. The returned value can be any data type including an array, a code block, or NIL. Each function must begin with a FUNCTION statement and contain at least one RETURN statement with an argument. Function declarations cannot be nested within other function definitions. A user-defined function can be used wherever standard functions are supported, including expressions.
The visibility of function names falls into two classes. Functions that are visible anywhere in a program are referred to as public functions and declared with a FUNCTION statement. Functions that are visible only within the current program (.prg) file are referred to as static functions and declared with a STATIC FUNCTION statement.
Static functions have filewide scope. Static functions limit visibility of a function name, thereby restricting access to the function. Because of this, subsystems defined within a single program (.prg) file can provide an access protocol with a series of public functions and conceal the implementation details of the subsystem within static functions and procedures. Since the static function references are resolved at compile time, they preempt references to public functions which are resolved at link time. This ensures that within a program file, a reference to a static function executes that function if there is a name conflict with a public function.
For more information on user-defined functions, variable declarations, and parameter passing, refer to the “Basic Concepts” chapter.
Notes
. Calling a user-defined function: Use the same notation to call a user-defined function as when calling a standard Harbour function: <idFunction>([<argument list>])
You can call a user-defined function within an expression or on a line by itself. If called on a line by itself, the return value is ignored.
You can also call a user-defined function as an aliased expression by prefacing it with an alias and enclosing it in parentheses: <idAlias>->(<idFunction>(<argument list>))
When you call a user-defined function as an aliased expression, the work area associated with <idAlias> is selected, the expression is executed, and the original work area is then reselected. You can specify an aliased expression on a line by itself, as you would any other expression.
A user-defined function in Harbour may call itself recursively. This means you can make a reference to a user-defined function in statements or expressions of the same user-defined function definition.
. Parameters: User-defined functions, like procedures, can receive parameters passed from a calling procedure, user-defined function, or DOS command line. A parameter is a place holder for a value or reference. In Harbour, there are two ways to express parameters: you can declare a list of local variable names as a part of the FUNCTION declaration (referred to as formal parameters), or you can specify a list of private variables in a separate PARAMETERS statement. Note that you cannot mix a declaration of formal parameters with a PARAMETERS statement. Attempting this will result in a fatal compiler error.
Functions receive parameters in the order passed. In Harbour, the number of parameters does not have to match the number of arguments passed. You can skip arguments or omit them from the end of the argument list. A parameter not receiving a value or reference is initialized to NIL. You can skip a parameter by passing NIL. If arguments are specified, PCOUNT() returns the position of the last argument passed. (If more arguments are passed than are parameters, they are ignored.)
Parameters specified in a user-defined function can receive arguments passed by value or reference. The default method for expressions and variables is by value. This includes variables that contain references to arrays and objects. All variables except field variables, when prefaced with the pass-by-reference operator (@), are passed by reference. Field variables cannot be passed by reference and are always passed by value.
Examples
. This example demonstrates a user-defined function that formats numeric values as currency: ? Currency( 1000 ) // Result: Þ1,000.00 FUNCTION Currency( nNumber ) LOCAL cNumber IF nNumber < 0 cNumber := TRANSFORM(-1 * nNumber, ; "999,999,999,999.99") cNumber := PADL("(Þ" + LTRIM(cNumber) + ")", ; LEN(cNumber)) ELSE cNumber := TRANSFORM(nNumber, ; "999,999,999,999.99") cNumber := PADL("Þ" + LTRIM(cNumber), ; LEN(cNumber)) ENDIF RETURN cNumber . This example demonstrates a user-defined function that takes a character string formatted as a comma-separated list and returns an array with one element per item: aList := ListAsArray("One, Two") // Result: {"One", "Two"} FUNCTION ListAsArray( cList ) LOCAL nPos // Define an empty array LOCAL aList := {} // DO WHILE (nPos := AT(",", cList)) != 0 // Add a new element AADD(aList, SUBSTR(cList, 1, nPos - 1)) cList := SUBSTR(cList, nPos + 1) ENDDO AADD(aList, cList) // // Return the array RETURN aList . This example checks for a skipped argument by comparing the parameter to NIL: FUNCTION MyFunc( param1, param2, param3 ) IF param2 == NIL param2 := "default value" ENDIF . . <statements> . RETURN NIL . This example uses the user-defined function, Currency() (defined above), as an aliased expression: USE Invoices NEW USE Customer NEW ? Invoices->(Currency(Amount))
Seealso
LOCAL, PARAMETERS, PCOUNT(), PRIVATE, PROCEDURE, RETURN