Files
Noja/docs/04_Functions.md
T
2022-08-18 15:53:19 +02:00

4.2 KiB

Functions

Function definition statements always start with the fun keyword, followed by it's name, argument list and then body.

Here are some examples of function definitions:

# No arguments
fun sayHelloToEveryone() {
    print('Hello, everyone!\n');
}

# Some arguments
fun sayHelloTo(name) {
    print('Hello, ', name, '!\n');
}

fun sayHelloToBoth(name1, name2) {
    print('Hello, ', name1, '!\n');
    print('Hello, ', name2, '!\n');
}

When function bodies only have one statement, you can drop the brackets

fun sayHelloToEveryone()
    print('Hello, everyone!\n');

fun sayHelloTo(name)
    print('Hello, ', name, '!\n');

fun sayHelloToBoth(name1, name2) {
    print('Hello, ', name1, '!\n');
    print('Hello, ', name2, '!\n');
}

Like if-else and while statements, they don't need an ending ;.

The evaluation of a function definition statement results in the definition of a variable who's name is the name of the defined function and it's value is the function itself. You may overwrite the variable or use it in an expression, although the only valid operation on it is a function call.

fun abc() {}

# Now "abc" is a function

abc = 10;

# Now it's an integer!

Functions calls and return values

To execute a function in an expression, it's name must be followed by an argument list enclosed in brackets (..). All functions return at least one value, which may be none when a function has no useful value to be returned.

To specify the return value of a function, one must use the return statement

fun myName() {
    # ..do stuff..
    return "Francesco";
}

fun add(a, b)
    return a + b;

when calling a function, the resulting value of the call will be the one evaluated by the last return statement.

fun add(a, b)
    return a + b;

six = add(2, 3) + 1; 

Note that a return statement must always end with a ;.

When a function doesn't return a value explicitly, then the none value is returned:

fun iDontReturnExplicitly() {
    1 + 2;
}

print(iDontReturnExplicitly(), '\n'); # Prints: none 

Multiple returns

Functions may return more than one value:

fun swap(a, b)
    return b, a;

When a calling a function with more than one return value in an expression, only the first return value is considered.

fun returnTwoThings()
    return 5, "I'm ignored";

print(1 + returnTwoThings(), '\n'); # Prints 6.

The way to use the additional return values is through an assignment to multiple variables

first, second = returnTwoThings();
print(first, '\n'); # Prints 5
print(second, '\n'); # Prints "I'm ignored"

An assignment to multiple variables is still an expression and it evaluates to the leftmost value

fun combine(a, b) 
    return (a+b), (a-b);

print((x,y = combine(3, 4))); # Prints 7.

Scoping

Functions are the only thing that creates a new scope. When variables are defined inside a function, they're relative to the function and the function only. When the function returns, the variable defined inside it are no longer available.

Closures

When defining a function, the scope of the parent context is captured and it's always accessible by the function's body. When functions are defined in the global scope, this means that they can always access global variables

name = "Francesco";

fun printName()
    print(name);

printName(); # Prints "Francesco"

name = "Giovanni";

printName(); # Prints "Giovanni"

But this mechanism is cooler than that. Consider the case were a function is defined inside another one

name1 = "Giovanni";
fun outerFunc() {
    name2 = "Francesco";
    fun innerFunc() {
        print(name1, " and ", name2, " are friends!\n");
    }
}

outerFunc(); # Prints: Giovanni and Francesco are friends!

now the inner function can access both the variables of the outer function and the global scope.

This also applies when the function is returned

name1 = "Giovanni";
fun outerFunc() {
    name2 = "Francesco";
    fun innerFunc() {
        print(name1, " and ", name2, " are friends!\n");
    }
    return innerFunc;
}

innerFunc = outerFunc();
innerFunc(); # Prints the same thing

But functions may never modify the captures scopes. Variables can only be defined relative to the local scope.

Type hints

..