Functions are declared using the def keyword. A function's signature has to be explicitly provided. Its arguments are type annotated, just like variables, and, if the function returns a value, the return type must be specified after an arrow ->.

A function has to be declared at the top level before it is called.

def foo(field a, field b) -> field {
    return a + b;

def main() -> field {
    return foo(1, 2);

A function can be generic over any number of values of type u32.

def foo<N>() -> field[N] {
    return [42; N];

def main() -> field[2] {
    field[2] res = foo();
    return res;

The generic parameters can be provided explicitly, especially when they cannot be inferred.

// a function to sum the N first powers of a field element
def sum_powers<N>(field a) -> field {
    field mut res = 0;
    for u32 i in 0..N {
        res = res + a ** i;
    return res;

def main(field a) -> field {
    // call `sum_powers` providing the explicit generic parameter `N := 5`
    return sum_powers::<5>(a);

If the return type of a function is the empty tuple (), the return type as well as the return statement can be omitted.

def main() {}