Function Declaration

Summary

Declares a function.

Syntax

returntype name([[type1] param1 [, [type2] param2 ... [, [...] [type3] param3]]]) {
    statement1;
    statement2;
    statement3;
}

Parameters

returntype
The type to restrict the expression for the return statement to.
name
The name of the function. This can be any valid identifier.
typeN
The type to restrict the parameter to. If no type is specified, the parameter's default type is `external`.
paramN
The name for the parameter. This can be any valid identifier. Optionally, a variadic parameter can be created if the parameter is prefixed with ...
statementN
The statement(s) to execute when the function is called.

Description

A function is a named set of instructions that can be executed over and over again with different possible inputs. Functions are commonly used for performing a specific task, and they can return a value. The value returned by a function is known as its return value, and the type of the return value is known as the return type.

The parameters for a function define the inputs for the function. Functions can be called with different inputs ("arguments") each time.

Functions can also return a value via the return statement. The return value can be any valid expression. When the function is called, the function call expression is replaced with the return value.

Overview

Function Declaration vs. Function Expression

A function can be either A) a function declaration and used where a statement is expected, or B) a function expression and used where an expression is expected.

Function Declaration
1
2
3
4
5
function foo() {
    return true;
}
 
foo();
Function Expression
1
2
3
4
5
var foo = function foo() {
    return true;
};
 
foo();

Thus, when used as an expression, functions can be passed to another function as an argument, returned from a function, or assigned to variables.

Assigning Function to Variable
1
2
3
var foo = function() {
    return true;
};
Returning a Function from a Function
1
2
3
4
5
6
7
8
9
10
function foo() {
    return function() {
        return 100;
    };
}
 
// Call twice.
// The first call returns the returned function, which gets called again,
// producing the result: 100
foo()();
Passing a Function as an Argument
1
2
3
4
5
6
7
function foo(bar) {
    return bar(); // returns 100
}
 
foo(function() {
    return 100;
});

In addition, a function expression can be immediately executed (IIFE - immediately-invoked function expression):

1
2
3
(function() {
    // Do something...
})();

In JavaScript, IIFEs were used to create a scope. However, with the scoping rules of JS++ (and especially its file scope), creating a scope with an IIFE is unnecessary.

Anonymous Functions

Function expressions can be anonymous functions. In other words, the function expression can be created without a name.

If the anonymous expression is assigned to a variable, it can be called using the variable's name.

Anonymous Function Assigned to Variable
1
2
3
4
5
var foo = function() { // this function was declared without a name
    return true;
};
 
foo(); // call using the name of the variable the function was assigned to
Anonymous Function Passed as Argument
1
2
3
4
5
6
7
function foo(bar) {
    bar(); // call using the name of the parameter the function was assigned to
}
 
foo(function() { // pass an anonymous function to 'foo'
    return true;
});

Note that function declarations cannot be anonymous and must always be declared with a name.

Parameters and Arguments

Variadic Parameters

Variadic parameters allow a function to take infinitely many arguments for a single parameter. The arguments supplied to the variadic parameter are stored as an array. To make a parameter a variadic parameter, prefix the parameter with ...

1
2
3
4
5
6
7
8
9
10
11
function add(...numbers) {
    int total = 0;
    foreach(int number in numbers) {
        total += number;
    }
     
    return total;
}
 
add(1, 2, 3); // 6
add(4, 5, 6); // 15

Since variadic parameters are stored as arrays, you can assign them to array types:

1
2
3
4
5
6
7
8
9
10
void add(...int numbers) {
    int[] args = numbers; // assign variadic parameter to int[] variable
 
    int total = 0;
    foreach(int x in args) {
        total += x;
    }
 
    return total;
}

Only one variadic parameter is allowed for each function.

Callback Parameters

Parameters can have a callback type:

1
2
3
4
5
6
7
8
9
import System;
 
void message(int(int, int) callback) { // 'callback' has type 'int(int, int)'
    Console.log(callback(1, 2));
}
 
message(int add(int firstNumber, int secondNumber) {
    return firstNumber + secondNumber;
});

In the above example, the message function takes one parameter named callback which has a callback type. The parameter expects a callback that returns type int and takes two int parameters.

When we call the message function, we send an argument that is a callback. The callback we send to the function matches the function signature expected for the callback parameter. In the example, we send an add callback function as an argument, and, when the message function calls the callback with the arguments 1 and 2, the add callback will execute, add the two numbers together, and return it.

Overloading

Basics

Functions can be overloaded in JS++. Overloading enables creating multiple functions of the same name but having different implementations.

Consider an overloaded add function:

1
2
3
4
5
6
7
8
9
10
11
12
13
function add(int a, int b) {
    return add(a, b, 0);
}
function add(int a, int b, int c) {
    return add(a, b, c, 0);
}
function add(int a, int b, int c, int d) {
    return a + b + c + d;
}
 
add(1, 2);    // 3
add(1, 1, 5); // 7
add(5, 10, 5, 10); // 30

Limitations on Overloading

Free functions will only overload if they are in the exact same scope.

For example, the following free functions will be overloaded:

1
2
void foo() {}
void foo(int a, int b) {}

The following free functions will not be overloaded:

1
2
3
4
void foo() {}
if (true) {
    void foo(int a, int b) {}
}

With external functions, if all return types for all overloads are external, all references to the function will be considered external:Unimplemented

1
2
3
4
function foo() {}
function foo(int a) {}
 
var foo2 = foo; // ok

However, if at least one overload is internal, all references to the function will be considered System.Function:Unimplemented

1
2
3
4
function foo() {}
void foo(int a) {}
 
var foo2 = foo; // error!

Closures

A closure is created when a function is declared inside another function. The inner function can access the variables and parameters of the outer function (even after the outer function returns).

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo(z) {
    int x = 1;
     
    function bar() {
        int y = 1;
         
        return x + y + z;
    }
     
    return bar();
}
 
foo(1); // 3

We can also rewrite the example so the inner function gets returned for the outer function, and, despite the outer function having returned already, the returned inner function can still access the variables and parameters of the outer function:

1
2
3
4
5
6
7
8
9
10
11
function foo(z) {
    int x = 1;
     
    return function bar() {
        int y = 1;
         
        return x + y + z;
    };
}
 
foo(1)(); // Call twice since first function returns a function. Result is: 3

Be careful with closures as they can be a source of memory leaks. If memory is not cleared, the compiler will generate an error. Unimplemented For more information, consult the closures documentation for closure memory leaks.

Differences to JavaScript

Unlike JavaScript, free functions in JS++ are not "hoisted". However, JS++ methods are. Thus, for free functions, the declaration must always precede the usage.

Furthermore, JS++ is block-scoped rather than function-scoped. Thus, functions are scoped to the nearest block rather than the nearest function.

See Also

Share

HTML | BBCode | Direct Link