Functions

Squirrel 2.2

Functions

Functions are first class values like integer or strings and can be stored in table slots, local variables, arrays and passed as function parameters. Functions can be implemented in Squirrel or in a native language with calling conventions compatible with ANSI C.

Function declaration

Functions are declared through the function expression

local a= function(a,b,c) {return a+b-c;}		
			

or with the syntactic sugar

function ciao(a,b,c)
{
    return a+b-c;
}		
			

that is equivalent to

this.ciao <- function(a,b)
{
    return a+b-c;
}
			

is also possible to declare something like

T <- {}
function T::ciao(a,b,c)
{
    return a+b-c;
}

//that is equivalent to write

T.ciao <- function(a,b,c)
{
    return a+b-c;
}

//or

T <- {
	function ciao(a,b,c)
	{
		return a+b-c;
	}
}
			

Default Paramaters

Squirrel's functions can have default parameters.

A function with default parameters is declared as follows:

        
function test(a,b,c = 10, d = 20)
{
	....
}
        
        

when the function test is invoked and the parameter c or d are not specified, the VM autometically assigns the default value to the unspecified parameter. A default parameter can be any valid squirrel expression. The expression is evaluated at runtime.

Function with variable number of paramaters

Squirrel's functions can have variable number of parameters(varargs functions).

A vararg function is declared by adding three dots (`...´) at the end of its parameter list.

When the function is called all the extra parameters will be accessible through the pseudo array called vargv.

vargv can only indexed with a numeric object(float or integer). The number of parameter contained in vargv is stored in the pseudo variable vargc.

Note that vargv is not a real object, it can't be assigned or passed as parameter.
function test(a,b,...)
{
	for(local i = 0; i< vargc; i++)
	{
		::print("varparam "+i+" = "+vargv[i]+"\n");
	}
}

test("goes in a","goes in b",0,1,2,3,4,5,6,7,8);
			  

Function calls

        
          exp:= derefexp ‘(‘ explist ‘)’
        
      

The expression is evaluated in this order: derefexp after the explist (arguments) and at the end the call.

Every function call in Squirrel passes the environment object ‘this’ as hidden parameter to the called function. The ‘this’ parameter is the object where the function was indexed from.

If we call a function with this syntax

table.foo(a)
			

the environment object passed to foo will be ‘table’

foo(x,y) // equivalent to this.foo(x,y)
			

The environment object will be ‘this’ (the same of the caller function).

Binding an environment to a function

while by default a squirrel function call passes as environment object 'this', the object where the function was indexed from. However, is also possible to statically bind an evironment to a closure using the built-in method closure.bindenv(env_obj). The method bindenv() returns a new instance of a closure with the environment bound to it. When an environment object is bound to a function, every time the function is invoked, its 'this' parameter will always be the previously bound environent. This mechanism is useful to implement callbacks systems similar to C# delegates.

Note

The closure keeps a weak reference to the bound environmet object, because of this if the object is deleted, the next call to the closure will result in a null environment object.

Free variables

Free variables are variables referenced by a function that are not visible in the function scope. In the following example the function foo() declares x, y and testy as free variables.

local x=10,y=20
testy <- “I’m testy”

function foo(a,b):(x,y,testy)
{
    ::print(testy);
    return a+b+x+y;
}
			

The value of a free variable is frozen and bound to the function when the function is created; the value is passed to the function as implicit parameter every time is called.

Tail recursion

Tail recursion is a method for partially transforming a recursion in a program into an iteration: it applies when the recursive calls in a function are the last executed statements in that function (just before the return). If this happenes the squirrel interpreter collapses the caller stack frame before the recursive call; because of that very deep recursions are possible without risk of a stack overflow.

function loopy(n)
{
    if(n>0){
        ::print(“n=”+n+”\n”);
        return loopy(n-1);
    }
}

loopy(1000);