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's signature has to be explicitly provided.

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 res = 0
    for u32 i in 0..N do
        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)

Functions can return multiple values by providing them as a comma-separated list.

def main() -> (field, field[3]):
    return 1, [2, 3, 4]

Variable declaration

When defining a variable as the return value of a function, types are provided when the variable needs to be declared:

def foo() -> (field, field):
    return 21, 42

def main():
    // a is declared here
    field a = 1
    // b is declared here
    a, field b = foo()