Functions

Functions are declared with the fn keyword.

Function declaration

fn add(a: int, b: int): int {
    return a + b;
}

Functions may also be marked export or extern:

export fn public_api(value: int): int {
    return value;
}

extern fn native_api(value: int): int;

An extern declaration has no body and ends with a semicolon.

A function declaration contains:

  1. fn
  2. function name
  3. parameter list
  4. return type
  5. function body

Syntax

fn name(parameters): return_type {
    statements
}

Parameters

Each parameter has a name and a type.

fn multiply(a: int, b: int): int {
    return a * b;
}

Return type

The return type follows :.

fn square(x: float): float {
    return x ** 2;
}

Return

Vesper uses an explicit return statement.

fn add(a: int, b: int): int {
    return a + b;
}

Calling functions

let result = add(10, 20);

Imported functions are called through their module alias:

import "math" as m;
let result = m.square(5.0);

Multiple arguments

fn sum3(a: int, b: int, c: int): int {
    return a + b + c;
}

let result = sum3(1, 2, 3);

Default parameters

Parameters can have default values.

fn power(x: float, exponent: int = 2): float {
    return x ** exponent;
}

The default is used when the argument is omitted.

let square = power(5.0);
let cube = power(5.0, 3);

Recursion

Functions can call themselves.

fn factorial(n: int): int {
    if (n <= 1) {
        return 1;
    }

    return n * factorial(n - 1);
}

let result = factorial(5);

The language implementation supports recursive function calls.

Forward calls

Function declarations are checked in a separate pass from function bodies, allowing calls to functions that are declared later in the source program.

let result = later();

fn later(): int {
    return 42;
}

The exact behavior of top-level execution and initialization should follow the current interpreter/compiler implementation.