Functions are the basic components of Kaya programs. They are defined by the following general scheme (the expression may be made up of many statements):
ReturnType functionName(arg1Type arg1name, ...) {
expression;
}
A simple example is this function, which totals its arguments:
Int total(Int a, Int b, Int c) {
return a+b+c;
}
A more complex example, which also demonstrates recursion (functions calling themselves) is the following function, which finds a number in the fibonacci sequence in an inefficient way.
Int fib(Int x) {
if (x == 0 || x == 1) {
return 1;
} else {
return fib(x-2)+fib(x-1);
}
}
Functions are ‘first-class’ objects, and so have types and can be passed as variables. For example, the type of fib
is Int(Int)
and the type of total
is Int(Int,Int,Int)
. The following function tests if all elements of an array match a user-supplied condition.
Bool allMatch([Int] xs, Bool(Int) test) {
// allMatch (hopefully obviously) has the type Bool([Int],Bool(Int))
for x in xs {
if (!test(x)) {
return false;
}
}
return true;
}
This function could be used like this:
Void main() {
allMatch([1,3,9,5,4,11],odd);
}
Bool odd(Int num) {
return (num % 2 != 0);
}
Constant functions
For convenience, functions that take no arguments can have the brackets omitted. This is intended to allow you to represent constant values.
program piprog;
import IO; // For the "get" function.
Float Pi {
return 3.14159265358979;
}
Void main {
putStr("Enter a radius: ");
r = Float(get(stdin));
putStrLn("Area is " + String(Pi*r*r));
}
Note that
stdin
is another constant function, which returns the standard input stream. Running this program gives:
$ ./piprog Enter a radius: 5 Area is 78.5398 $
A further shorthand for constant functions is
Float Pi = 3.141592653589793;
This is not a global variable, as it cannot be modified.
Function parameters
Function parameters are normally passed as a shallow copy (i.e. the parameter itself is copied, but references inside are not. Therefore:
Void increment(Int a) {
a = a+1;
putStrLn("a = "+a);
}
Void main() {
a = 5;
increment(a);
putStrLn("a = "+a);
}
/* output is
a = 6
a = 5
*/
Incrementing the variable inside the function does not affect its value outside the function. However, because it’s only a shallow copy:
Void increment([Int] a) {
a[0] += 1;
putStrLn("a[0] = "+a[0]);
}
Void main() {
a = [5];
increment(a);
putStrLn("a[0] = "+a[0]);
}
/* output is
a[0] = 6
a[0] = 6
*/
To avoid modifying the values ‘inside’ a parameter, you can use the copy function from the standard prelude to make a deep copy of the parameter. (Warning: this can be very slow for complex data structures, and is usually unnecessary)
Void increment([Int] a) {
a[0] += 1;
putStrLn("a[0] = "+a[0]);
}
Void main() {
a = [5];
increment(copy(a));
putStrLn("a[0] = "+a[0]);
}
/* output is
a[0] = 6
a[0] = 5
*/
Conversely, if you would like the function to be able to completely modify its parameters, you can use the var
keyword to pass by reference.
Void increment(var Int a) {
a = a+1;
putStrLn("a = "+a);
}
Void main() {
a = 5;
increment(a);
putStrLn("a = "+a);
}
/* output is
a = 6
a = 6
*/