Skip to content

Closures and Function Types

Chloë Strainge edited this page Oct 15, 2026 · 2 revisions

Closures and function types

An anonymous fn expression is a function value. Creating it does not run its body. It captures live bindings from its creation environment. Omit the return annotation only when the closure returns (). Use : any for a dynamic result or an explicit type for a fixed result, just as for named functions.

fn sequence($start: Integer): fn(): Integer
{
    fn (): Integer
    {
        $start = $start + 2
        $start
    }
}
let $next = sequence 10
echo ($next) ($next)
12 14

The captured local remains alive after sequence returns. Two closures capturing the same binding observe its writes. A new let of the same name creates another binding and does not replace an old capture. Each evaluation of an anonymous function creates a new callable identity; copying it retains that identity.

Prototype contracts

fn(Integer): String is a first-class function type. Parameter names are not part of the prototype. A missing result in fn(Integer) means ().

type Formatter = fn(Integer): String
fn decorate($n: Integer): String { "#" + String($n) }
fn render($format: Formatter, $value: Integer): String { $format $value }
let $style: Formatter = `decorate
echo (render $style 23)
echo (render fn ($n: Integer): String { "item=" + String($n) } 8)
#23
item=8

Annotations accept compatible named references and anonymous functions. Parameter and result checks still apply when the callback runs. General any signatures can participate where dynamic checks can enforce the required contract; they do not disable those checks.

A type declaration around a prototype is nominal, like other named types. Parenthesize the whole function type when unioning the function value with another kind: (fn(): String) | String. Otherwise a | after the colon belongs to the function's result type.

Bare backtick references use executable String representation. Prototype annotations adapt them to callable contracts. Display text alone is not a replacement for an anonymous closure's identity or captured state.

Storing callbacks

Callbacks can live in arrays, hashes, fields, and other closures. Use $callback as a value in an argument position; use ($callback) to call it with no arguments. A method reference such as `$items.pop additionally keeps its live receiver.


Related: Methods · Variables and scope

Clone this wiki locally