Skip to main content

Parameter Passing

Parameter Passing

An important features of procedures is their support for parameter passing. This is the mechanism by which you can pass values (or variables) to a procedure as parameters. Of course, parameter passing is not required; for example, procedures with no parameter passing could be used to generate a random number or to return the system date in a format other than the default format. Commonly, however, procedures do use parameter passing.

To set up parameter passing, specify:

  • An actual parameter list on the procedure call.

  • A formal parameter list on the procedure definition.

When Caché executes a user-defined procedure, it maps the parameters in the actual list, by position, to the corresponding parameters in the formal list. Thus, the value of the first parameter in the actual list is placed in the first variable in the formal list; the second value is placed in the second variable; and so on. The matching of these parameters is done by position, not name. Thus, the variables used for the actual parameters and the formal parameters are not required to have (and usually should not have) the same names. The procedure accesses the passed values by referencing the appropriate variables in its formal list.

The actual parameter list and the formal parameter list may differ in the number of parameters:

  • If the actual parameter list has fewer parameters than the formal parameter list, the unmatched elements in the formal parameter list are undefined. You can specify a default value for an undefined formal parameter, as shown in the following example:

    Main
       /* Passes 2 parameters to a procedure that takes 3 parameters */
       SET a="apple",b="banana",c="carrot",d="dill"
       DO ListGroceries(a,b)
       WRITE !,"all done"
    ListGroceries(x="?",y="?",z="?") {
       WRITE x," ",y," ",z,!   }
  • If the actual parameter list has more parameters than the formal parameter list, a <PARAMETER> error occurs, as shown in the following example:

    Main
       /* Passes 4 parameters to a procedure that takes 3 parameters. 
          This results in a <PARAMETER> error  */
       SET a="apple",b="banana",c="carrot",d="dill"
       DO ListGroceries(a,b,c,d)
       WRITE !,"all done"
    ListGroceries(x="?",y="?",z="?") {
       WRITE x," ",y," ",z,!   }

If there are more variables in the formal list than there are parameters in the actual list, and a default value is not provided for each, the extra variables are left undefined. Your procedure code should include appropriate IF tests to make sure that each procedure reference provides usable values. To simplify matching the number of actual parameters and formal parameters, you can specify a variable number of parameters.

The maximum number of actual parameters is 254.

When passing parameters to a user-defined procedure, you can use passing by value or passing by reference. You can mix passing by value and passing by reference within the same procedure call.

  • Procedures can be passed parameters by value or by reference.

  • Subroutines can be passed parameters by value or by reference.

  • User-defined functions can be passed parameters by value or by reference.

  • System-supplied functions can be passed parameters by value only.

Passing By Value

To pass by value, specify a literal value, an expression, or a local variable (subscripted or unsubscripted) in the actual parameter list. In the case of an expression, Caché first evaluates the expression and then passes the resulting value. In the case of a local variable, Caché passes the variable’s current value. Note that all specified variable names must exist and must have a value.

The procedure’s formal parameter list contains unsubscripted local variable names. It cannot specify an explicit subscripted variable. However, specifying a variable number of parameters implicitly creates subscripted variables.

Caché implicitly creates and declares any non-public variables used within a procedure, so that already-existing variables with the same name in calling code are not overwritten. It places the existing values for these variables (if any) on the program stack. When it invokes the QUIT command, Caché executes an implicit KILL command for each of the formal variables and restores their previous values from the stack.

In the following example, the SET commands use three different forms to pass the same value to the referenced Cube procedure.

 DO Start()
 WRITE "all done"
Start() PUBLIC {
 SET var1=6
 SET a=$$Cube(6)
 SET b=$$Cube(2*3)
 SET c=$$Cube(var1)
 WRITE !,"a: ",a," b: ",b," c: ",c,!
 QUIT 1
 }
Cube(num) PUBLIC {
 SET result = num*num*num
 QUIT result
}

Passing By Reference

To pass by reference, specify a local variable name or the name of an unsubscripted array in the actual parameter list, using the form:

.name

With passing by reference, a specified variable or array name does not have to exist before the procedure reference. Passing by reference is the only way you can pass an array name to a procedure. Note that you cannot pass a subscripted variable by reference.

  • Actual parameter list: The period preceding the local variable or array name in the actual parameter list is required. It specifies that the variable is being passed by reference, not passed by value.

  • Formal parameter list: No special syntax is required in the formal parameter list to receive a variable passed by reference. The period prefix is not permitted in the formal parameter list. However, an ampersand (&) prefix is permitted before the name of a variable in the formal parameter list; by convention this & prefix is used to indicate that this variable is being passed in by reference. The & prefix is optional and performs no operation; it is a useful convention for making your source code easier to read and maintain.

In passing by reference, each variable or array name in the actual list is bound to the corresponding variable name in the function’s formal list. Passing by reference provides an effective mechanism for two-way communication between the referencing routine and the function. Any change that the function makes to a variable in its formal list is also made to the corresponding by-reference variable in the actual list. This also applies to the KILL command. If a by-reference variable in the formal list is killed by the function, the corresponding variable in the actual list is also killed.

If a variable or array name specified in the actual list does not already exist, the function reference treats it as undefined. If the function assigns a value to the corresponding variable in the formal list, the actual variable or array is also defined with this value.

The following example compares passing by reference with passing by value. The variable a is passed by value, the variable b is passed by reference:

Main
   SET a="6",b="7"
     WRITE "Initial values:",!
     WRITE "a=",a," b=",b,!
   DO DoubleNums(a,.b)
     WRITE "Returned to Main:",!
     WRITE "a=",a," b=",b
DoubleNums(foo,&bar) {
  WRITE "Doubled Numbers:",!
  SET foo=foo*2
  SET bar=bar*2
  WRITE "foo=",foo," bar=",bar,!
  QUIT
  }

The following example uses passing by reference to achieve two-way communication between the referencing routine and the function through the variable result. The period prefix specifies that result is passed by reference. When the function is executed, result in the actual parameter list is created and bound to z in the function’s formal parameter list. The calculated value is assigned to z and passed back to the referencing routine in result. The & prefix to z in the formal parameter list is optional and non-functional, but helps to clarify the source code. Note that num and powr are passed by value, not reference. This is an example of mixing passing by value and passing by reference:

Start ; Raise an integer to a power.
 READ !,"Integer= ",num  QUIT:num="" 
 READ !,"Power= ",powr   QUIT:powr=""
 SET output=$$Expo(num,powr,.result)
 WRITE !,"Result= ",output
 GOTO Start
Expo(x,y,&z)
 SET z=x
 FOR i=1:1:y {SET z=z*x}
 QUIT z

Variable Number of Parameters

A procedure can specify that it accepts a variable number of parameters. You do this by appending three dots to the name of the final parameter; for example, vals.... This parameter must be the final parameter in the parameter list. It can be the only parameter in the parameter list. This ... syntax can pass multiple parameters, a single parameter, or zero parameters.

Spaces and new lines are permitted between parameters in the list, as well as before the first parameter and after the final parameter in the list. Whitespace is not permitted between the three dots.

To use this syntax, specify a signature where the name of the final parameter is followed by .... The multiple parameters passed to the method through this mechanism can have values from data types, be object-valued, or be a mix of the two. The parameter that specifies the use of a variable number of parameters can have any valid identifier name.

ObjectScript handles passing a variable number of parameters by creating a subscripted variable, creating one subscript for each passed variable. The top level of the variable contains the number of parameters passed. The variable subscripts contain the passed values.

This is shown in the following example. It uses invals... as the only parameter in the formal parameter list. ListGroceries(invals...) receives a variable number of values passed by value:

Main
   SET a="apple",b="banana",c="carrot",d="dill",e="endive"
   DO ListGroceries(a,b,c,d,e)
   WRITE !,"all done"
ListGroceries(invals...) {
  WRITE invals," parameters passed",!
   FOR i=1:1:invals {
      WRITE invals(i),! }
   }

The following example uses morenums... as the final parameter, following two defined parameters. This procedure can receive a variable number of additional parameters, starting with the third parameter. The first two parameters are required, either as defined parameters DO AddNumbers(a,b,c,d,e) or as placeholder commas DO AddNumbers(,,c,d,e):

Main
   SET a=7,b=8,c=9,d=100,e=2000
   DO AddNumbers(a,b,c,d,e)
   WRITE "all done"
AddNumbers(x,y,morenums...) {
  SET sum = x+y
  FOR i=1:1:$GET(morenums, 0) {
     SET sum = sum + $GET(morenums(i)) }
  WRITE "The sum is ",sum,!
  QUIT
  }

The following example uses morenums... as the final parameter, following two defined parameters. This procedure receives exactly two parameter values; the morenums... variable number of additional parameters is 0:

Main
   SET a=7,b=8,c=9,d=100,e=2000
   DO AddNumbers(a,b)
   WRITE "all done"
AddNumbers(x,y,morenums...) {
  SET sum = x+y
  FOR i=1:1:$GET(morenums, 0) {
     SET sum = sum + $GET(morenums(i)) }
  WRITE "The sum is ",sum,!
  QUIT
  }

As specified, AddNumbers(x,y,morenums...) can receive a minimum of two parameters and a maximum of 255. If you supply defaults for the defined parameters AddNumbers(x=0,y=0,morenums...) this procedure can receive a minimum of no parameters and a maximum of 255.

The following example uses nums... as the only parameter. It receives a variable number of values passed by reference:

Main
   SET a=7,b=8,c=9,d=100,e=2000
   DO AddNumbers(.a,.b,.c,.d,.e)
   WRITE "all done"
AddNumbers(&nums...) {
  SET sum = 0
  FOR i=1:1:$GET(nums, 0) {
     SET sum = sum + $GET(nums(i)) }
  WRITE "The sum is ",sum,!
  QUIT sum
  }

When a variable parameter list params... receives parameters passed by reference and passes the params... to a routine, the intermediate routine can add additional parameters (additional nodes in the params array) that will also be passed by reference. This is shown in the following example:

Main
   SET a(1)=10,a(2)=20,a(3)=30
   DO MoreNumbers(.a)
   WRITE !,"all done"
MoreNumbers(&params...) {
   SET params(1,6)=60
   SET params(1,8)=80
   DO ShowNumbers(.params) }
ShowNumbers(&tens...) {
   SET key=$ORDER(tens(1,1,""),1,targ)
   WHILE key'="" {
     WRITE key," = ",targ,!
     SET key=$ORDER(tens(1,1,key),1,targ)
   }
  }

The following example shows that this args... syntax can be used in both the formal parameter list and in the actual parameter list. In this example, a variable number of parameters (invals...) are passed by value to ListNums, which doubles their values then passes them as invals... to ListDoubleNums:

Main
   SET a="1",b="2",c="3",d="4"
   DO ListNums(a,b,c,d)
   WRITE !,"back to Main, all done"
ListNums(invals...) {
  FOR i=1:1:invals {
    WRITE invals(i),!
    SET invals(i)=invals(i)*2 }
  DO ListDoubleNums(invals...)
  WRITE "back to ListNums",!
ListDoubleNums(twicevals...)
  WRITE "Doubled Numbers:",!
  FOR i=1:1:twicevals {
    WRITE twicevals(i),! }
  QUIT
  }

For specifics about methods that can accept a variable number of parameters, see the section “Variable Numbers of Arguments in Methods” in the “Methods” chapter of Using Caché Objects.

FeedbackOpens in a new tab