Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


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

Subsections


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 [*].)


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 [*], for a discussion of local variables.) As in most programming languages, actual arguments match with formal parameters left-to-right:

function diff(a, b) a-b

...

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 the function definition formal includes an = expression, an actual argument for that formal parameter can be left out when calling the function. The actual argument is instead initialized using expression (expression is referred to as the formal's default). As you saw above, you can define diff as:

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

You can instead define diff with:

    function diff(a=0, b) a-b
so that only b is required in a call. This makes diff a ``negation'' function. A call like:
    diff(6)
is now illegal, because 6 matches a and not b; but the call
    diff(b = 6)
is legal and returns -6. Arguments which have defaults can simply be left out, as long as their absence is denoted. The previous invocation can also be written as:
    diff(,6)
The first argument is purposefully left out, therefore it is assigned the default value. You can test for missing arguments using the missing() function. (See § 6.5, page [*].)

Note that while match-by-position and match-by-name arguments can be intermixed, a parameter must be specified only 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, because 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 reference to the actual argument. In this case, the actual argument (outside of the function) can be modified with the ref parameter. (See § 4.6, page [*] regarding val assignment and § 3.8, page [*], 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 [*] 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, when writing a function you do not have to worry about parameter passing efficiency. This is because all values in Glish are stored and then accessed using copy-on-write. (See § 3.10, page [*].) Copy-on-write means that if two values are assigned to be equal then they 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 being returned is never modified after the return statement, and as a result, return values are not 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 this case if abs is called with a non-numeric value Glish detects the type clash and generates 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. The function num_args returns the number of arguments with which it is called. The nth_arg function 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 is 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 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 returns 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   Contents   Index
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15