Functions
⚠️ TODO
Example:
function square(x) => x ^^ 2;
function square2(x: int) : int
{
return x ^^ 2;
}
assert(square(3) == 9);
assert(square2(3) == 9);
Normal Functions
⚠️ TODO
Parameter Type Inference
Function parameters can have an explicit type, or can restrict the allowed argument types using one of the following means.
Typed Parameters
function foo(x: int) => 2 * x;
Generic Typed Parameters
struct S(T: type) { var value: T; }
function foo(x: S) => 2 * x.value;
Constrained Parameters
Example:
function foo(x: isIntegral) => 2 * x;
Partially Typed Function Parameters
Example:
function foo(x: function(x: int)) => x(2);
Unconstrained Parameters
Example:
function foo(x) => 2 * x;
Type Aliases
The type of a particular parameter can be assigned to a type alias that then can be used to define or restrict other parameter types. The compiler will attempt to pattern match this type alias to determine its value from all eligible parameters that use it to define their type.
Example:
function sum(a: isIntegral alias T, b: T[])
{
var result = a;
for (val; b) result += val;
return result;
}
Parameter Type Aliases
In some situations, it is desirable to be able to force several parameters to (partially) share the same type. This is supported by adding a type alias to one of the parameters, which can then be used to constrain the types of the other parameters.
function fun(a: isIntegral alias T, b: T, c: T[]);
Parameter Reverse Overload resolution
When passing a function overload, a generic function or an object with a
generic operator[call] to a parameter that has a function or partial function
type, the compiler will perform a reverse-overload resolution on the passed
expression to select a callable that matches the parameter type.
Example:
function foo(x: int) => x * 2;
function foo(x: float) => x * 4.0f;
function bar(fun: function(int), x: int) => fun(x);
assert(bar(foo, 10) == 20);
Return Type Inference
The return type of a function that does not explicitly define one will be
inferred by computing the common type of all values passed as return values
to a return statement within the function body. If no value is returned, the
return type will be inferred as void. It is illegal to declare a function
with no body and no explicit return type.
Variadic Parameters
⚠️ TODO
Tuple Based
function printFormatted(format: string, arguments...) {}
printFormatted("The %s is %s", "answer", 42);
Array Slice Based
function addItems(items...: int[]) {}
addItems(1, 2, 3);
addItems([1, 2, 3]);
addItems(items: [1, 2, 3]);
Static Array Based
function setCoordinates(coordinates...: int[3]) {}
setCoordinates(1, 2, 3);
setCoordinates([1, 2, 3]);
C-Style
@extern("C") function printf(format: const(char)*, ...): int;
Universal Function-Call Syntax
When calling a normal function, instead of writing all arguments in parenthesis, the first argument may instead be written in front of the function, resembling a method call. Conversely, a method can also be called by referencing the method name as a regular function outside of the aggregate and passing the aggregate as the first argument.
This alternative syntax naturally allows to write "extension functions", as well as functional call chains.
Example:
struct Point {
var x: int;
var y: int;
method clear() { x = 0; y = 0; }
}
function moveRight(ref point: Point, amount: int)
{
point.x += amount;
}
var pt = Point(10, 10);
// regular function call
moveRight(5);
assert(pt == Point(15, 10));
// regular method call
pt.clear();
// function called as method
pt.moveRight(5);
assert(pt == Point(15, 10));
// method called as function
clear(pt);
Inline Functions
Functions can be defined anonymously as inline-expressions. Both the regular
syntax using an explicit function body and the lambda syntax using => are
supported.
Example:
var fun1 = (x, y) { return x + y; }
var fun2 = (x, y) => x + y;
var fun3 = x => 2 * x;
assert(fun1(2, 3) == 5);
assert(fun2(2, 3) == 5);
assert(fun3(3) == 6);
Closures
Prepending an inline function expression with a list of variable names accessible in the current scope creates a closure that captures or references the listed variables. Internally, a closure is represented as an inline defined struct that stores the captured variables as fields and has a "call" operator that contains the function body of the closure.
Example:
var local = 42;
var fun1 = [local] (x) { return x + local; }
var fun2 = [local] (x) => x + local;
var fun3 = [ref local] (x) => local += x;
assert(fun1(10) == 52);
assert(fun2(10) == 52);
fun3(2);
assert(local == 44);