Procedures and User-Defined Functions
Procedures and functions allow you to keep commonly used code in a single place and call it throughout your application whenever you need it. This makes your code easier to read and easier to maintain because a change can be made once in the procedure rather than multiple times in your programs.
In Visual FoxPro, procedures look like this:
PROCEDURE myproc
* This is a comment, but it could be executable code
ENDPROC
Traditionally, procedures contain code that you write to perform an operation, and functions do some operations and return a value. In Visual FoxPro, functions are similar to procedures:
FUNCTION myfunc
* This is a comment, but it could be executable code
ENDFUNC
You can include procedures and functions in a separate program file or at the end of a program file that contains normal program code. You cannot have normal executable program code included in a program file following procedures and functions.
If you include your procedures and functions in a separate program file, you can make these procedures and functions accessible in your program by using the SET PROCEDURE TO command. For example, for a file called FUNPROC.PRG, use this command in the Command window:
SET PROCEDURE TO funproc.prg
Calling a Procedure or Function
There are two ways to call a procedure or function in your programs:
Use the DO command. For example:
DO myproc
-or-
Include a set of parentheses after the function name. For example:
myfunc( )
Each of these methods can be expanded by sending or receiving values from the procedure or function.
Sending Values to a Procedure or Function
To send values to procedures or functions, you include parameters. The following procedure, for example, accepts a single parameter:
PROCEDURE myproc( cString )
* The following line displays a message
MESSAGEBOX ("myproc" + cString)
ENDPROC
**Note **Including the parameters inside parentheses in a procedure or function definition line, for example,
PROCEDURE myproc(cString)
, indicates that the parameter is scoped locally to the procedure or function. You can also allow a function or procedure to accept locally scoped parameters with LPARAMETERS.
Parameters work identically in a function. To send a value as a parameter to this procedure or to a function, you can use a string or a variable that contains a string, as shown in the following table.
Passing Parameters
Code | Comments |
---|---|
|
Calls a procedure and passes a literal string or character variable. |
|
Calls a function and passes a copy of a character variable or literal string. |
Note If you call a procedure or function without using the DO command, the UDFPARMS setting controls how parameters are passed. By default, UDFPARMS is set to VALUE, so copies of the parameters are passed. When you use DO, the actual parameter is used (the parameter is passed by reference), and any changes within the procedure or function are reflected in the original data, regardless of the setting of UDFPARMS.
You can send multiple values to a procedure or function by separating them with commas. For example, the following procedure expects three parameters: a date, a character string, and a number.
PROCEDURE myproc( dDate, cString, nTimesToPrint )
FOR nCnt = 1 to nTimesToPrint
? DTOC(dDate) + " " + cString + " " + STR(nCnt)
ENDFOR
ENDPROC
You could call this procedure with this line of code:
DO myproc WITH DATE(), "Hello World", 10
Receiving Values from a Function
The default return value is true (.T.), but you can use the RETURN command to return any value. For example, the following function returns a date that is two weeks later than date passed to it as a parameter.
FUNCTION plus2weeks
PARAMETERS dDate
RETURN dDate + 14
ENDFUNC
The following line of code stores the value returned from this function to a variable:
dDeadLine = plus2weeks(DATE())
The following table lists the ways you can store or display values returned from a function:
Manipulating Return Values
Code | Comments |
---|---|
|
Stores the value returned by the function to a variable. |
|
Prints the value returned by the function in the active output window. |
Verifying Parameters in a Procedure or Function
It's a good idea to verify that the parameters sent to your procedure or function are what you expect to receive. You can use the TYPE( ) and PARAMETERS( ) functions to verify the type and number of parameters sent to your procedure or function.
The example in the previous section, for instance, needs to receive a Date type parameter. You can use the TYPE( ) function to make sure the value your function receives is the right type.
FUNCTION plus2weeks( dDate )
IF TYPE("dDate") = "D"
RETURN dDate + 14
ELSE
MESSAGEBOX( "You must pass a date!" )
RETURN { - - } && Return an empty date
ENDIF
ENDFUNC
If a procedure expects fewer parameters than it receives, Visual FoxPro generates an error message. For example, if you listed two parameters, but you call the procedure with three parameters, you'll get an error message. But if a procedure expects more parameters than it receives, the additional parameters are simply initialized to false (.F.). Because there is no way to tell whether the last parameter was set to false (.F.) or omitted, the following procedure checks to make sure the appropriate number of parameters was sent:
PROCEDURE SaveValue( cStoreTo, cNewVal, lIsInTable )
IF PARAMETERS( ) < 3
MESSAGEBOX( "Too few parameters passed." )
RETURN .F.
ENDIF
IF lIsInTable
REPLACE (cStoreTo) WITH (cNewVal)
ELSE
&cStoreTo = cNewVal
ENDIF
RETURN .T.
ENDPROC
Converting the NUMONLY Program to a Function
NUMONLY.PRG, the example program discussed in Constructing a Small Program, can be made more robust and useful by creating a function for the part of the program that removes the non-numeric characters from a string.
Sample Procedure to Return Numeric Characters from a String
Code | Comments |
---|---|
|
Start of the function, which accepts a character string. |
|
Create a string that has only the numeric characters from the original string. |
|
Return the string that has only numeric characters. |
|
End of the function. |
In addition to allowing you to use this code in multiple situations, this function makes the program easier to read:
SCAN
REPLACE FieldName WITH NumbersOnly(FieldName)
ENDSCAN
Or, even more simply:
REPLACE ALL FieldName WITH NumbersOnly(FieldName)
See Also
Constructing a Small Program | Character Functions | Basic Programming Concepts | Creating Programs vs. Inputting Manually | Creating Programs | TYPE( ) | PARAMETERS( ) | RETURN