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
DO myproc WITH cTestString
DO myproc WITH "test string"
Calls a procedure and passes a literal string or character variable.
myfunc("test string")
myfunc( cTestString )
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
var = myfunc( )
Stores the value returned by the function to a variable.
? myfunc( )
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
FUNCTION NumbersOnly( cMixedVal )
Start of the function, which accepts a character string.
  cNumOnly = ""
  FOR nCnt = 1 TO LEN(cMixedVal)
   cCharacter = ;
  SUBSTR(cMixedVal, nCnt, 1)
    IF ISDIGIT(cCharacter)
       cNumOnly = ;
   cNumOnly + cCharacter
    ENDIF
   ENDFOR
Create a string that has only the numeric characters from the original string.
RETURN cNumOnly
Return the string that has only numeric characters.
ENDFUNC
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