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


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

Subsections


The Function Body

The body of a Glish function has one of two forms:

expression

{ statement1 statement2 ... }
When a function using the first form is called, it evaluates expression and returns the result as the value of the function call. With the second form, the statements are collected in a statement block (See § 5 and § 5.9), and then the statements are executed sequentially. The value of the last statement executed is returned. Most statements do not have a value associated with them. If the last executed statement is one of these, the function call returns F. If the last executed statement is an expression (See § 5.1, page [*]) or a return statement (See § 5.6, page [*]) then the call returns the value of the expression.

Functions may call themselves either directly or indirectly; there is no limit on the recursive invocation depth other than the available memory.


Scoping

Glish supports three levels of scoping: function, global, and local.


function Scope

By default, all variables which are assigned within a function are local to that function; they have function scope. So for example:
    function my_sin(y)
        { 
        x := sin(y)
        return x
        }
In this example, the x that is assigned to in the function is local to this function. It will not modify a global x if one is defined. Note however that another Glish value is used in this function, sin. This is a global function, and because global variables are accessible in functions, the global sin variable can be used. If sin is modified:
    function my_func(x)
        {
        sin := 2^x
        return sin
        }
then sin will be a variable that is local to this function, and the global sin will not be modified.


global Scope

A global variable persists throughout the execution of the Glish program, and sometimes functions must be able to modify these variables as well as access their values. For example, the following:
    x := 1
    function bump_x() { global x +:= 1 }
    bump_x()
    print x
will print the value 2. Here the global keyword is used to specify that a function variable should correspond to a global variable. If the global keyword is left out, x will be local to the function. When assignment is made to these function variables which have been tagged as global, the global variable of the same name is modified. The global keyword can also be used without the assignment:
    function bump_x_2()
        {
        global x
        x +:= 1
        }
Here bump_x_2 and bump_x are functionally equivalent. In either case, subsequent use of the variable within the function will actually operate on the global variable of the same name. The syntax of the global statement mirrors that of local (See § 5.9, page [*]), but global's semantics are the inverse of local's.


local Scope

The local scope variable specifies that a particular variable is local to the current statement block. This variable was introduced in § 5.9. In this example:
    function trix(x)
        {
        y := x^2
        local z := x^3
        {
            local y := x^4, w
            w := 100
            print x,y,z,w
        }
        print x,y,z
        }
the local in front of the assignment of z is not needed because by default assigned variables in a function default to function scope. Here x, y, and z are local to the function block. Another y is introduced in the inner statement block along with w; these are local to the inner block. The invocation of trix(2) results in this output:
2 16 8 100
2 4 8

Variables of local and function scope usually cease to exist once the statement block with which they are associated exits. (See § 6.6.2 for some exceptions.) When the function is next called, the variable is recreated but with no trace of its former value. All function parameters are local to the function body.


wider Scope

Dividing variables into either global variables that are accessible from anywhere or local variables that are only accessible within a give function is often sufficient. There are times when access is needed to variables which are defined in a wider scope but that are are still not global. Here is a simple example:
    function object(x)
        {
        value := x
        ret := [=]
        ret.get := func ( )  { return value }
        ret.set := func (nv) { wider value
                               value := nv }
        return ret
        }
This example creates as simple function closure; the object function defines two functions which share a common variable. Without the wider statement, the set function will not be able to modify the shared variable, i.e. value.

The wider statement allows modification access to a variable defined in a wider scope. Without this statement, modification of a variable makes it local to the function by default.


Persistent Local Variables

There are two ways local variables can survive beyond the end of the function call that created them. Here ``survive" does not mean that subsequent calls to the function see the previous value, but that the value continues to exist after the initial function call returns.

The first way is by returning a reference to the variable. This used to be the preferred way of returning big values in Glish, but because copy-on-write (See § 6.4.3, page [*]) was added to Glish, you do not need to worry about this issue. References, however, can still be returned (See § 3.8, page [*]).

The second way local variables survive is if the function body or a statement block with local variables executes a whenever statement. The whenever statement specifies actions to be taken at a future time, asynchronously to the execution of the statements in the Glish program (See § 5.10.2, page [*], and particularly Chapter 7, page [*]). For example, the following:

    # Waits for x->foo, prints y
    # when it comes
    func announce_upon_foo(x, y)
        {
        whenever x->foo do
            print y
        }
    announce_upon_foo(x, 14)
    work()
    more_work()
    etc()
will print 14 whenever x generates a foo event. The value of y (which, being a parameter, is local to the function body) is remembered even after the call to announce_upon_foo returns. You can later add another call:
    announce_upon_foo(x, "hi there")
and when x generates foo events both 14 and "hi there" will be printed (in an indeterminate order).

When the function executes a whenever all of its local variables are preserved and can be accessed within the statements of the whenever's body. If those statements modify the variables then the modifications persist:

    func announce_upon_foo(x, y)
        {
        whenever x->foo do
            {
            print y
            y +:= 1
            }
        }
    announce_upon_foo(x, 14)
    announce_upon_foo(x, 7)
will print 14 and 7 upon x's first foo event, 15 and 8 upon the second, and so on.

Persistent local variables are particularly important for subsequences. (See § 7.12, page [*].)


next up previous contents index
Next: Events Up: Functions Previous: Missing Parameters   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