Functions, Generics, and Recursion
Functions are predeclared, so forward calls, direct recursion, mutual recursion, nested declarations, exports, generic parameters, and callable references are available.
Function declarations
A block-bodied function ends with its result expression.
fn add(left: int, right: int) -> int {
left + right
}
add(20, 22);
Expression-bodied functions
fn name(...) = expression; is the compact form.
fn square(value: int) -> int = value * value;
square(6);
Parameters and return schemas
Parameters use name: Schema; a result schema follows ->.
fn describe(name: string, score: int) -> string {
name + ":" + score
}
describe("Ada", 42);
Public functions
pub fn exports a function from a source module.
pub fn answer() -> int {
42
}
answer();
External function declarations
A semicolon-only function declaration describes a host function supplied by the embedding runtime.
fn host_log(message: string);
host_log("ready");
Forward calls
A function can call another function declared later in the source.
fn first(value: int) -> int {
second(value) + 1
}
fn second(value: int) -> int {
value * 2
}
first(20);
Direct recursion
Recursive functions use ordinary named calls and the configured script call-depth limit.
fn factorial(value: int) -> int {
if value <= 1 => {
1
} else => {
value * factorial(value - 1)
}
}
factorial(5);
Mutual recursion
Predeclaration also permits mutually recursive functions.
fn is_even(value: int) -> bool {
if value == 0 => { true } else => { is_odd(value - 1) }
}
fn is_odd(value: int) -> bool {
if value == 0 => { false } else => { is_even(value - 1) }
}
is_even(10);
Nested functions
Functions may be declared inside function bodies and can capture outer locals.
fn make_offset(base: int) {
fn add(value: int) -> int {
value + base
}
add
}
let add_two = make_offset(2);
add_two(40);
Generic functions
Angle brackets declare generic type parameters.
fn identity<T>(value: T) -> T {
value
}
let number = identity::<int>(42);
let text = identity::<string>("rss");
Explicit type arguments
Turbofish syntax ::<...> supplies explicit type arguments at a named call or function reference.
fn identity<T>(value: T) -> T {
value
}
let answer = identity::<int>(42);
let int_identity = identity::<int>;
int_identity(answer);
Higher-order generics
Callable schemas can contain generic parameters.
fn identity<T>(value: T) -> T {
value
}
fn apply<T>(mapper: fn(T) -> T, value: T) -> T {
mapper(value)
}
apply::<int>(identity, 42);