Functions
Introduction
Functions are blocks of code that you can reuse throughout your program. They may receive input parameters and they always output something. The syntax is as follows:
Functions may be associated to objects. Any function associated to an object may be used (called) by the object itself or by other objects. This means that functions are public (they are visible to the outside world).
Note: functions must be defined after the states.
Return statement
Use the return
statement to stop executing the function and to return some value to the caller. Example:
// This function will return the double of input parameter x
fun double(x)
{
return 2 * x;
Console.print("This line will never be executed.");
}
If no value is specified after the return
keyword, the function will be stopped and its return value will be null
. Additionally, if no return
statement is found, then the return value will also be null
.
Note: an object state may also contain one or more return
statements to stop the execution of its code. However, return values must not be specified in that context, since states do not return values.
Simple example
In the example below, we have an object called Calculator
with two functions: greet()
and sum()
. greet()
takes no input parameters and just greets the user. On the other hand, sum()
takes two input parameters, a
and b
, and returns the sum a + b
:
object "Calculator"
{
fun greet()
{
Console.print("Hello! I am a Calculator!");
}
fun sum(a, b)
{
return a + b;
}
}
In function sum()
, variables a
and b
hold the input data and are only visible inside the function.
Now, let's create a program that uses this Calculator
. Remember that the functions defined above can be called by any object, including Application
:
object "Application"
{
calculator = spawn("Calculator");
state "main"
{
// greet the user
calculator.greet();
// do some computation
result = calculator.sum(5, 7);
Console.print(result);
// we're done!
Application.exit();
}
}
The output of the above program is:
Notice that the Application
does not need to know how the functions of the Calculator
are implemented. It just needs to know what they do. This means that you may change the implementation of the Calculator
without changing the Application
, and the end-result will stay the same.
Recursive functions
In SurgeScript, a function is said to be recursive when it calls itself within its code. Recursion can be useful in many ways; namely, when you define a problem in terms of itself. In mathematics, the factorial of a non-negative integer number n
, denoted as n!
, is such an example:
One interesting example of recursion that arises in computer science is called the binary search algorithm. Given a sorted Array, the binary search finds the position of a target value without having to inspect the whole collection. In the example below, bsearch()
is a recursive function:
object "Binary Search"
{
// Given an array sorted in ascending order, find()
// finds the position of the target value in the array.
// It returns its index, or -1 if the target is not found.
fun find(array, value)
{
return bsearch(array, value, 0, array.length - 1);
}
// Performs a binary search in array[start..end]
fun bsearch(array, value, start, end)
{
// get the middle point
mid = start + Math.floor((end - start) / 2);
// compare the middle point to the target value
if(start > end)
return -1; // target not found
else if(value == array[mid])
return mid; // found the target value
else if(value < array[mid])
return bsearch(array, value, start, mid - 1);
else
return bsearch(array, value, mid + 1, end);
}
}
Recursive functions must have at least one base case. A base case is a scenario that does not need recursion to solve the problem. In the factorial example, the base case is n <= 1
(the factorial is 1). In the binary search example, the base case is start > end
, meaning that the array is empty and the target value cannot be found, or value == array[mid]
, meaning that the target value has been found at mid
.
How to understand recursion
A sage once said: "to understand recursion, you must first understand recursion".
Constructors and destructors
In SurgeScript, constructors and destructors are special functions that are called whenever objects are created and destroyed, respectively. It's not mandatory to define them, but it may be useful to do so (you may want to set up things in your constructors, for example). Neither may receive any arguments (to set up objects with parameters, take a look at chaining).
Let's take our Calculator
again. In the following example, constructor()
is called automatically whenever a Calculator
object is created. Likewise, destructor()
is called automatically when the object is destroyed.
object "Calculator"
{
fun constructor()
{
Console.print("Creating a Calculator...");
}
fun destructor()
{
Console.print("Destroying a Calculator...");
}
fun greet()
{
Console.print("Hello! I am a Calculator!");
}
fun sum(a, b)
{
return a + b;
}
}
Now, if we run the Application
of the previous section without any modification, the output of the program will be:
Note that, for any object, its constructor()
runs before its main state.