Skip to main content

Function

  • Can return nothing or a value
  • Can modify the data in the database when called from an operation (run-time verification)
  • Can get called from queries, operations, or functions
  • If the return type isn't specified explicitly, it's a unit (no return value)

Short form

function f(x: integer): integer = x * x;

Full form

function f(x: integer): integer {
return x * x;
}

Return type not specified

When the return type isn't specified, it's considered a unit:

function f(x: integer) {
print(x);
}

Default parameter values

Parameters of functions can have default values. The default parameters get used if you don't specify the parameters in the function call.

function f(user: text = 'Bob', score: integer = 123) {...}
...
f(); // means f('Bob', 123)
f('Alice'); // means f('Alice', 123)
f(score=456); // means f('Bob', 456)

Named function arguments

One could also specify function arguments by names.

function f(x: integer, y: text) {}
...
f(x = 123, y = 'Hello');

Using a function as a value

If you want to pass a function to another function, then you can use the function as a value by using the following syntax:

() -> boolean
(integer) -> text
(byte_array, decimal) -> integer

Within the parentheses, you specify the function input type of the passed function after the arrow follows the function's return type.

An example could look like this:

function filter(values: list<integer>, predicate: (integer) -> boolean): list<integer> {
return values @* { predicate($) };
}

Partial function app

You can use the wildcard symbol * to create a reference to a function (to obtain a value of a function).

function f(x: integer, y: integer) = x * y;

val g = f(*); // Type of "g" is (integer, integer) -> integer
g(123, 456); // Invocation of f(123, 456) via "g".

Extendable functions

You can declare a function as extendable by adding @extendable before the function declaration. You can define an arbitrary number of extensions for an extendable function by expressing @extend before the function declaration.

In the example below, function f is a base function, and functions g and h are extension functions.

@extendable function f(x: integer) {
print('f', x);
}

@extend(f) function g(x: integer) {
print('g', x);
}

@extend(f) function h(x: integer) {
print('h', x);
}

When you call the base function, all its extension functions get executed, and the base function itself gets executed. However, Extendable functions support a limited set of return types, and this behavior depends on the return type.

The following behavior applies to the different return types:

Unit

  • All extensions get executed.
  • The base function is always executed at the end.

Boolean

  • Extensions get executed individually until some of them return "true."
  • The base function gets executed if all extensions return "false."
  • The result of the last executed function gets returned to the caller.

T?

  • Similar to a boolean. Extensions execute until the first non-null result is returned to the caller.

list<T>

  • All extensions get executed.
  • The base function gets executed at the end.
  • The concatenation of all lists gets returned to the caller.

map<K, V>

  • Similar to list<T>, the union of all maps gets returned to the caller but fails if there is a key conflict.