Functions
Top-level functions, nested functions, typed signatures, closures, capture rules, and task functions in Walrus.
Functions are central to Walrus. They are named, typed, and can be nested to create closures. Walrus also supports task functions through @task, which marks work that should be started with spawn and resolved with await.
Top-level functions
fn abs(x: int) -> int:
if x < 0:
return 0 - x
return xParameters and return types are written explicitly.
Nested functions
You can declare a function inside another function:
fn makeAdder(k: int) -> fn(int) -> int:
fn add(x: int) -> int:
return x + k
return addThat nested function becomes a closure value when it captures names from the outer scope.
Immutable captures
Most closure examples start with immutable capture:
fn makeAdder(k: int) -> fn(int) -> int:
fn add(x: int) -> int:
return x + k
return addHere, k is captured and read by the returned function.
Mutable captures
Use var when the nested function must mutate a captured local:
fn counter() -> fn() -> int:
var i = 0
fn next() -> int:
i += 1
return i
return nextThis is also where ownership rules matter. Copy values are captured cheaply. Owned values move into escaping closures. Borrowed values only work when the closure stays local.
Function types
Walrus exposes function types directly in annotations:
fn makeAdder(k: int) -> fn(int) -> int
fn counter() -> fn() -> intTask Functions
Use @task when a function is meant to participate in Walrus' thread-aware task model:
@task
fn buildStuff() -> int:
return 5Task functions are still ordinary typed functions in source code, but semantically they mean:
- this function is schedulable work
- it should be started with
spawn - its result is consumed through a task handle and
await
Starting a task
let task = spawn buildStuff()
let result = await taskNormal calls are rejected
This is intentionally invalid:
@task
fn buildStuff() -> int:
return 5
fn main() -> int:
return buildStuff()Walrus reports:
task functions must be started with spawnThreaded intent
Task functions are part of the language's move toward threaded execution. In the current first pass, they still run through a synchronous runtime path internally, but the language shape is already correct for future worker-thread scheduling.