7.2. Function Arguments

When a function is called, the arguments in the call are mapped to the arguments specified in the function definition on a one-to-one basis. The Gamma engine evaluates the arguments and maps the results of those evaluations to each function argument name. Since Gamma is abstractly typed, there is no need to specify a data type in the function definition. If a particular data type is required within the function, then the function body can check for the type using the type predicate, type-p.

7.2.1. Variable number of arguments

It is possible to create a function that takes a variable number of arguments. The last argument in a function's argument list may be made to act as a "catch-all" or vararg argument which collects all remaining arguments provided in the function call as a list. For example,

function f (x, y...)

creates a function with 2 mandatory arguments, the second of which can have one or more values. If this function is called as f (1,2), then x will have the value 1, and y will have the value (2), that is, a list containing one element whose value is 2. If this function is called as f (1,2,3,4,5), then x will be 1, and y will be (2 3 4 5), a list of four elements. If this function is called as f(1), then an error would occur because y is not optional.

7.2.2. Optional arguments

Gamma allows optional arguments at the end of an argument list. An optional argument is specified by appending a question mark (?) to an argument in the function's argument list. All arguments after the first optional argument are implicitly optional as well. If the caller wants to provide a value to an optional argument, then the caller must also provide values for all preceding optional arguments. If an optional argument is not provided during the call, then the argument will take on the value UNDEFINED, which must be dealt with within the body of the function. A default value for an optional argument can also be provided in the function definition. For example,

function f (x, y?, z=5)

creates a function with 1 mandatory argument and two optional arguments. The argument y has no default value, and z has a default value of 5. This function could be called as f(1), f(1,2) or f(1,2,3).

7.2.3. Protection from evaluation

Any function argument can be protected from evaluation by an exclamation mark (!) before the argument name in the function's argument list. For example,

function f (x, !y)

creates a function with two mandatory arguments , the second of which will not be evaluated when it is called. If this function were called as f (2+2, 3+3) then x would have the value of 4, and y would have as its value the expression 3+3. y could be evaluated using eval(y) to produce the value 6.

7.2.4. Variable, optional, unevaluated arguments

A variable argument can also be made optional. If so, and if it is not evaluated, then all the arguments which are collected into its list will not be evaluated either. For example,

function f (!y...? = 17)

creates a function with one optional argument named y. The argument y is not evaluated, and may take any number of values, passed as a list. If no argument is specified to the function, then y will have the value of 17. If, instead of 17 the default is set to nil, no default will be assigned. This syntax effectively gives a way to pass a list of arguments of any length to a funtion.

7.2.5. Examples

The following program shows example functions with argument lists similar to those described above.

#!/usr/cogent/bin/gamma

function variable_args (x, y...)
{
  princ("---- Output from variable_args(x, y...) ---- \n");
  princ("The first arg: ", x, "\n");
  with a in y do
    {
      princ("One of the variable args: ", a, "\n");
    }
  princ("\n");  
}

function optional_args (x, y?, z=5)
{
  princ("---- Output from optional_args(x, y?, z=5) ---- \n");
  if (undefined_p(y))
    y = "This value has not been defined.";
  princ("The first arg: ", x, "\n");
  princ("The second arg: ", y, "\n");
  princ("The third arg: ", z, "\n");
  princ("\n");  
}

function no_eval(x, !y)
{
  princ("---- Output from no_eval(x, !y) ---- \n");
  princ("This argument was evaluated: ", x, "\n");
  princ("This argument was not evaluated: ", y, "\n");
  princ("\n");  
}

function many_args (fixed_arg, !y?... = nil)
{  
  princ("---- Output from many_args(fixed_arg, !y?... = nil) ---- \n");
  princ("fixed_arg: ", fixed_arg, "\n");
  princ("y: ", y, "\n");
  princ("The first y arg: ", car(y), "\n");
  with a in cdr(y) do
    {
      princ("The next y arg: ", a, "\n");
    }
  princ("\n");
}

variable_args("hello", 9, "world", 4 + 7, #x);
optional_args(1);
optional_args(1, 2);
optional_args(1, 2, 3);
no_eval(2+2, 3+3);
many_args("Fixed", "hello", 9, "world", 4 + 7, #x);

The output of this program is as follows:

---- Output from variable_args(x, y...) ---- 
The first arg: hello
One of the variable args: 9
One of the variable args: world
One of the variable args: 11
One of the variable args: x

---- Output from optional_args(x, y?, z=5) ---- 
The first arg: 1
The second arg: This value has not been defined.
The third arg: 5

---- Output from optional_args(x, y?, z=5) ---- 
The first arg: 1
The second arg: 2
The third arg: 5

---- Output from optional_args(x, y?, z=5) ---- 
The first arg: 1
The second arg: 2
The third arg: 3

---- Output from no_eval(x, !y) ---- 
This argument was evaluated: 4
This argument was not evaluated: (+ 3 3)

---- Output from many_args(!y?... = nil) ---- 
One of the args: hello
One of the args: 9
One of the args: world
One of the args: (+ 4 7)
One of the args: 'x