Skip to content

Guide 4 of 36

Functions

Functions, closures, generators and async functions.

On this page

Basic Functions

fn greet(name: str) -> str {
    "Hello, {name}!"
}

fn add(a: int, b: int) -> int {
    a + b   // implicit return — last expression is the return value
}

Explicit Return

fn absolute(x: int) -> int {
    if x < 0 {
        return -x
    }
    x
}

No Return Type

Functions that don't return a value omit the -> Type:

fn say_hello(name: str) {
    print("Hello, {name}!")
}

Parameters

Type Annotations

fn process(x: int, y: f64, name: str) -> str {
    "{name}: {x}, {y}"
}

Named Arguments

fn create_user(name: str, age: int, email: str) -> User {
    User { name, age, email }
}

// Call with named arguments
create_user(name: "Alice", age: 30, email: "[email protected]")

Function types can also expose a named-call interface. This is useful for callbacks and Verniz components:

fn TodoList(items: [Todo], row: fn(item: Todo) -> View) -> View {
    <ul>{for todo in items { <row item={todo} /> }}</ul>
}

The label is erased after named arguments are reordered, so it does not change type compatibility: a function declared as fn todo_row(todo: Todo) -> View can be passed where fn(item: Todo) -> View is expected. The older fn(Todo) -> View spelling remains valid and positional-only. A function type must use names for every parameter or for none of them.

Method calls accept named arguments too. Named arguments are resolved before types are known, so the method name selects the signature: when exactly one impl in the program (or in the standard library) declares a method of that name whose parameters cover every label used, the call is reordered like a free function and omitted defaults are filled in. If several declarations with different parameter lists match, the call is ambiguous and reported as TE131; call it positionally. A method nobody declares is left untouched.

impl Box {
    fn scale(self, by: int = 1, plus: int = 0) -> int { self.n * by + plus }
}

b.scale(plus: 4, by: 2)   // by = 2, plus = 4
b.scale(plus: 1)          // by keeps its default

Default Values

Parameters can have explicit defaults, and name?: T is the concise form for an optional parameter whose default is nil:

fn Card(children?: fn() -> View) -> View {
    <section>{children?.()}</section>
}

The declarator makes the parameter itself optional. This distinction matters for function types: callback?: fn() -> View is an optional function, while callback: fn() -> View? is a required function with an optional return.

callback?.(args) evaluates the callback once. When it is nil, it returns nil without evaluating args; otherwise it calls the value directly. The spelling callback?() keeps the existing ? propagation semantics and is not an optional call.

Lambdas / Closures

Lambdas use the |params| expr syntax:

// Single expression
let double = |x| x * 2
let add = |a, b| a + b

// With type annotations
let square = |x: int| -> int { x * x }

// Multi-line body
let process = |x: int| -> int {
    let y = x * 2
    y + 1
}

Closures Capture Variables

let multiplier = 3
let multiply = |x| x * multiplier  // captures `multiplier`
print(multiply(5))  // 15

Higher-Order Functions

Functions can take functions as parameters and return functions:

fn apply(f: fn(int) -> int, x: int) -> int {
    f(x)
}

fn make_adder(n: int) -> fn(int) -> int {
    |x| x + n
}

let add5 = make_adder(5)
print(add5(10))  // 15

Methods

Methods are defined inside impl blocks. See Data Structures for details.

struct Circle {
    radius: f64,
}

impl Circle {
    fn area(self) -> f64 {
        3.14159 * self.radius * self.radius
    }

    fn new(radius: f64) -> Circle {
        Circle { radius }
    }
}

let c = Circle { radius: 5.0 }
print(c.area())

Decorators

Functions can be annotated with decorators:

@test
fn test_addition() {
    assert_eq(2 + 2, 4, "basic addition")
}

@memoize
fn fibonacci(n: int) -> int {
    if n <= 1 { n } else { fibonacci(n - 1) + fibonacci(n - 2) }
}

@deprecated("use new_function() instead")
fn old_function() {
    // ...
}

See Decorators for the full list.

DOCS / FEEDBACK

Did this page leave a question?

Tell us where the explanation lost you. Documentation is part of the language experience.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enespt-br