next up previous contents index
Next: Missing Parameters Up: Functions Previous: Function Names

Function Parameters

    Each function definition includes zero or more formal parameters, enclosed within ()'s. Each formal looks like:

type name = expression
type and = expression are optional. (formal's have one other form, ``...", discussed in § 6.4.4, page gif.)

Parameter Names

 

  name serves as the name of a local variable that during a function call is initialized with the corresponding actual argument. (See § 6.6.1, page gif, for a discussion of local variables.) As in most programming languages,   actual arguments are match with formal parameters left-to-right:

function diff(a, b) a-b

tex2html_wrap_inline15512

diff(3, 7)

matches 3 with a and 7 with b. Argument   matching can also be done ``by name":
    diff(b=1, a=2)
matches 1 with b and 2 with a.

Parameter Defaults

  If in the function definition a formal includes   = expression then when calling the function an actual argument for that formal can be left out, and the formal will instead be initialized using expression. expression is referred to as the formal's default. As we saw above, we could define diff as:

    function diff(a, b=1) a-b
in which case a call with only one argument would match that argument with a and initialize b to 1. A call using by-name   argument matching, though, could not specify b and not a, since a has no default:
    diff(b = 3)
is illegal.

We could instead have defined diff with:

    function diff(a=0, b) a-b
in which case when only b is specified in a call diff becomes the ``negation" function. A call like:
    diff(6)
is now illegal, since 6 matches a and not b; but the call
    diff(b = 6)
is legal and returns -6. Arguments   which have defaults can also simply be left out, as long as their absence is denoted. The previous invocation could also be written as:
    diff(,6)
Since the first argument is purposefully left out, it gets assigned the default value. You can test for missing arguments using the missing() function (§ 6.5, page gif).

Note that while match-by-position and match-by-name arguments can be intermixed, a parameter must   only be specified once. For example,

    diff(3, 4, a=2)
is illegal because a is matched twice, first to 3 and then to 2. Furthermore, once a match-by-name argument is given no more match-by-position arguments can be given, since their position is indeterminate:
    diff(a = 3, 2)
is illegal, since it's unclear what parameter 2 is meant to match.

Parameter Types

  A formal parameter definition can also include a type. Presently, the type is one of ref, const, or val. The type indicates the relationship between the actual argument and the formal parameter.

  If the formal parameter's type is ref then the formal is initialized as a ref reference to the actual argument, and can be used to change its value if the actual argument is a variable or record field (via a val assignment; see § 4.6, page gif). See § 3.8, page gif, for a full discussion of references.

    The val parameter type indicates that the parameter can be modified, but changes won't be reflected in the actual parameter which is passed into the the function. The default type for parameters is val.

  If the type is const, then it's initialized as a const value. A const parameter cannot be modified in the course of executing the function. Attempts to modify const parameters result in errors (see § 3.9, page gif for a discussion of const values).

Using ref Parameters

  Here is an example of a function with a ref parameter that increments its argument:

    function bump(ref x)
        {
        val x +:= 1
        }
After executing:
    y := 3
    bump(y)
y's value is 4. Note though that the following call:
    bump(3)
is perfectly legal and does not change the value of the constant 3 to 4!

Here's another example of using a ref parameter:

    # sets any elements of x > a to 0.
    func remove_outliers(ref x, a)
        {
        x[x > a] := 0
        }
 

Parameter and Return Value Efficiency

      For the most part, the person writing a function does not have to worry about parameter passing efficiency. This is a result of the fact that all values in Glish are stored so that access is done using copy-on-write (see § 3.10, page gif). Copy-on-write means that if two values are assigned to be equal then they will share the same underlying storage until one is modified.

This same mechanism is used when passing parameters or returning values. The default parameter type is val, but the parameter is only really copied if the parameter is modified in the function. So large parameters are only copied if necessary. Using a const parameter type provides a way to ensure that a given parameter does not change and, as a result, is not copied. With return values, the value is never modified as in the function block after the return statement, and as a result, return values will not be copied in the process of returning from the function.

Future Directions

  In the future Glish will support more explicit typing of parameters. For example, it will be possible to define a function like:

    function abs(val numeric x)
in which case if abs is called with a non-numeric value Glish will detect the type clash and generate an error.

Extra Arguments

 

You can write functions that take a variable number of parameters by including the special parameter   ``..." (called ellipsis) in the function definition. For example, here's a function that returns the sum of all its arguments,   regardless how many there are:

    func total(...)
        {
        local result := 0
        for ( i in 1:num_args(...) )
            result +:= nth_arg(i, ...)
        return result
        }

Two functions are available for dealing with variable argument lists.  

num_args   returns the number of arguments with which it was called,     and nth_arg   returns a copy of the argument specified by its first argument, with the first argument numbered as 0. For example,

    num_args(6,2,7)
returns 3 and
    nth_arg(3, "hi", 1.023, 42, "and more")
returns 42.  

    There's a temptation to expect num_args and nth_arg to return information about ``..." if they're not given an argument list, but presently they do not. Probably they will be changed to do so in the future.

  Note that the only operation allowed with ``..." is to pass it as an argument to another function. It cannot otherwise appear in an expression. When passing it to a function, it is expanded into   a list of const references to the actual arguments matched by the ellipsis. For example,  

    func many_min(x, ...)
        {
        if ( num_args(...) == 0 )
            return x
        else
            {
            ellipsis_min := many_min(...)

            if ( ellipsis_min < x )
                return ellipsis_min
            else
                return x
            }
        }
returns the minimum of an arbitrary number of arguments.

  When an ellipsis is used in a function definition then any parameters listed after it must be matched by name (or by default). Furthermore, the corresponding arguments must come after those to be matched by the ellipsis. For example, given:

    func dump_ellipsis(x, ..., y)
        {
        for ( i in num_args(...) )
            print i, nth_arg(i,...)
        }
both of the following calls are illegal:
    dump_ellipsis(1, 2, 3)
    dump_ellipsis(1, y=2, 3)
In the first y is not matched, and in the second the actual argument 3 is not matched (in particular, it is not matched by the ellipsis). The following, though, is legal:
    dump_ellipsis(1, 2, y=3)
and results in the ellipsis matching the single argument 2.

    An ellipsis can also have a default value specified. This value will be used as the value for any arguments which are purposefully left out. In the following,

    func add(...=0)
        {
        local ret := 0;
        for ( i in num_args(...) )
            ret +:= nth_arg(i,...)
        }
add is defined so that any arguments which are purposefully left out will be set to zero. So the following invocation,
    print add(1,2,,,5)
prints 8. The two arguments between the 2 and the 5 default to 0.

    An ellipsis can be used to construct a vector. This allows all of the parameters to be captured as a vector:

    func args(...) { return [...] }
this will return the parameters as a vector. So given the following invocations,
    args(1,5,8)
    args(4,3:5,1)
the result of the first is [1, 5, 8], and the result of the second is [4, 3, 4, 5, 1]. It is important to note, however, that if one of the arguments is not an array value, e.g. a record, an error results.

   


next up previous contents index
Next: Missing Parameters Up: Functions Previous: Function Names

Thu Nov 13 16:44:05 EST 1997