Getting Started | Documentation | Glish | Learn More | Programming | Contact Us |
Version 1.9 Build 1556 |
|
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.
Glish supports three levels of scoping: function, global, and local.
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.
x := 1 function bump_x() { global x +:= 1 } bump_x() print xwill 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.
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.
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.
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 .)