Skip to content

Functional

Type

Functional is a collection of types that can hold a function or a closure. To denote the type of function that takes parameters S, T (U, V, ...) and has a return type R, the following syntax is used:

(S, T) -> R

The return type is mandatory, even if it equals Unit. If the function takes no parameters, the parentheses are empty:

() -> R

Assignability

To initialize a variable of a functional type, one can use an anonymous function, non-member function, or a protocol method.

Given

function foo(x: Number, y: Text) returns Boolean -> {
    return x.toText() == y;
}

The following assignments are OK because the types match

var a: (Number, Text) -> Boolean = foo;
var b: (Number) -> Text = function(x: Number) returns Text -> x.toText();

But these are not

var q: (Number, Number) -> Boolean = foo;        // ERROR, 2nd argument type mismatch
var r: (Number, Text, Number) -> Boolean = foo;  // ERROR, missing argument
var s: (Number) -> Boolean = foo;                // ERROR, extra argument
var t: (Number, Text) -> Number = foo;           // ERROR, incorrect return type

The functional type (P_1, P_2, ... P_n) -> R is assignable to (Q_1, Q_2, ..., Q_m) -> S (but not necessarily vice versa) if the following conditions are satistifed:

  • n = m
  • for each i from 1 to n, Q_i is assignable to P_i
  • R is assignable to S

In other words, one can assign a function that takes contravariant (wider) types as arguments, and returns covariant ( narrower) type.

Given

union U { Number, Text }
function fun1(u: U) returns Text -> { return u.toText(); }
function fun2(a: Number) returns U -> { return a; }
function fun3(a: Number) returns Number -> { return a; }
function fun4(a: Number) returns U -> { return a; }

The following assignments are OK

var a: (Number) -> Text = fun1; // OK, Number is narrower than U
var b: (Number) -> U = fun3;   // OK, U is wider than Number

However, var b: (U) -> U = fun2 is not allowed because U is wider than Number, and var d: (Number) -> Number = fun4 is not allowed because Number is narrowed than U.

Protocol functions may be assigned as well, since they close over this ( see Closures).

protocol [p] Proto() {
    function foo(x: Number) -> {}

    permission [p] bar(y: Number) {}

    function implicit() -> {
        var a: (Number) -> Unit = foo;
    }

    function explicit() -> {
        var a: (Number) -> Unit = function(b: Number) returns Unit -> { this.bar['a'](b); };
    }
}

Actions cannot be assigned to a functional variable (so a function containing var a: (Number) -> Unit = bar is illegal).

Invocation

To invoke a functional simply supply the comma-separated list of arguments in parentheses as if it was a regular function.

struct A {
    x: (Number) -> Number
}

function apply(a: A, x: Number, b: (Number, Number) -> Number, y: Number, z: Number) returns Number -> {
    return a.x(x) + b(y, z);
}