Chapter 4: Functions and local variables

4.1. Function declaration

As shown in chapter 1 (in section 1.6.), a libfawk script normally consists of multiple functions. Function naming has the same rules as variable naming (see chapter 2). A function needs to have a name that is unique within the script.

The order of functions in the script does not matter: code can call functions that are not yet defined. There is no need for forward declarating functions.

4.2. Return value

Every function has a return value. There are two ways for returning from a function:

The function will return NIL when executing the implicit return and no value is assigned to the function name .

For example the following function pi() returns the value of pi and main() will print it:
example program ch4_ex1
function pi();
begin
	pi := 3.141592654;
end;

function main(ARGV);
begin
	fawk_print(pi());
end;

4.3. Function parameters

A function may list zero or more parameters in its definition in the parenthesis. Parameters are identified by their names:

function foo(bar, baz)
begin
	foo := bar+baz;
end;

In this example bar and baz are function parameters to foo(). Within foo() any reference to bar and baz will access the function parameter. If there was a global variable on the same name, it is unaccessible from foo(), because the parameter on the same name shadows the global variable.

Scalar values are passed by copy. That means at the time of the call, the caller supplied values are copied into new memory locations designated for the parameters of the call instance. If the function changes a the value of parameter, that affects only this copy, not the original version at the caller:
example program ch4_ex2
function foo(prm);
begin
	{ this prints 5 }
	fawk_print(prm);

	{ this changes prm to 6 (but caller's variable is unaffected) }
	prm := prm + 1;

	{ this prints 6 }
	fawk_print(prm);
end;

function main(ARGV);
begin
	a := 5;

	foo(a);

	{ this prints 5 }
	fawk_print(a);
end;

Note: arrays are passed by reference and are not copied. See chapter 5.

This is all true when a libfawk script calling a libfawk script function. When a libfawk script calling a C function there is an extra case: if the function parameter is a variable prefixed with & on the caller side, a reference is passed - example is delete(&var) where we want delete() to get the variable itself, not the value of the variable.

4.4. Excess parameters: local variables

The caller usually supplies exactly as many parameters as the function was defined with. The caller must not supply more parameters than the function has. But the caller may supply less parameters, in which case the parameters that are not supplied by the caller are initialized to NIL on function entry:
example program ch4_ex3
function foo(a;b;    c);
begin
	c := a+b;
	c := c + 1;
	foo := c;
end;

function main(ARGV);
begin
	{ this prints 6 }
	fawk_print(foo(2, 3));
end;

In this example only a and b of foo() are passed by the caller. c is still a parameter, which means it is not a global variable. Then foo() uses c as a temporary variable for calculating the result. Parameters defined but not passed are automatically initialized to have the NIL value.

This usage of parameter c is called a "local variable". As a convention it is recommended to add a few spaces between the parameters that are expected from the caller and the parameters intended for local variables in the function definition (for code clarity).

4.5. Excess parameters: optional parameters

Another use of the same mechanism is having optional parameters that the caller may or may not fill in:
example program ch4_ex4
function scale(val; factor);
begin
	if (factor = '') then factor := 5;
	scale := val*factor;
end;

function main(ARGV);
begin
	{ this prints 15 }
	fawk_print(scale(3));

	{ this prints 6 }
	fawk_print(scale(3, 2));
end;

Function scale detects if factor is passed by looking at its value: if it is NIL, it is not passed so it picks the default value of 5.

4.6. Function references

It is possible to save a function reference in a variable and call the function using the variable:
example program ch4_ex5
function big();
begin
	fawk_print('big');
end;

function small();
begin
	fawk_print('small');
end;

function main(ARGV);
begin
	a := 10;
	if a > 5 then
		f := big
	else
		f := small;

	{ prints that f is a function and prints the name of the function f points to }
	fawk_print(f);

	{ calls either big or small, whichever is stored in f }
	f();
end;

Note: the difference between retrieving the function reference and calling the function is the paranthesis: if there is parentesis opening after the name of the function, it is a function call. If there is no parenthesis, just the function name, it is then a reference to the function.

This syntax is similar to function call vs. function address in C.

4.7. Variable argument function

Some functions may need to take a variable number of arguments and decide how to process them runtime. Libfawk provides VARARG[] support for this. Place the special argument name ... in the function's argument list and it will be turned into a local array called VARARG[] that eats up all remaining caller arguments, indexed from 0 up:
example program ch4_ex6
function foo(a; b; ...; n);
begin
	fawk_print_cell(a, b,  VARARG, n, length(VARARG));
	for n := 0 to length(VARARG)-1 do
		fawk_print(n, VARARG[n]);
end;

function main(ARGV);
begin
	foo('p1', 5, 10, 20, 'p2');
end;

After the call, in foo(), a is "p1", b is 5, VARARG[] is [0]=10, [1]=20, [2]="p2" and n is NIL.

The ... argument splits the argument list so it has three sections: