5.1.13. Blocks

This tutorial covers block declarations, passing blocks to functions, the pipe <| operator, simplified => syntax, call syntax, and invoke() for local block variables.

5.1.13.1. Declaring a block

Blocks are anonymous functions prefixed with $():

var blk = $(a, b : int) => a + b
print("{invoke(blk, 3, 4)}\n")    // 7

5.1.13.2. Blocks as function arguments

Use block in the parameter type. Inside the function, call blocks directly — just like regular functions:

def do_twice(action : block) {
    action()           // call syntax — preferred
    action()
}

With typed parameters and return:

def apply_to(value : int; transform : block<(x:int):int>) : int {
    return transform(value)    // call syntax, not invoke
}

5.1.13.3. The pipe operator

Use <| to pass a trailing block argument:

do_twice() {
    print("hello!\n")
}

5.1.13.4. Simplified blocks

When a block has a single expression body, use =>:

let result = apply_to(5, $(x) => x * x)   // 25

5.1.13.5. Call syntax vs invoke

Inside a function that receives a block parameter, use call syntax:

def filter(arr : array<int>; predicate : block<(x:int):bool>) {
    for (v in arr) {
        if (predicate(v)) {      // call syntax: predicate(v)
            print("{v} ")
        }
    }
}

For local block variables, use invoke():

var blk = $(a, b : int) => a + b
print("{invoke(blk, 3, 4)}\n")

5.1.13.6. Capture rules

Blocks capture outer variables by reference and are stack-allocated. They cannot be stored in containers or returned from functions — use lambdas for that.

See also

Functions in the language reference.

Full source: tutorials/language/13_blocks.das

Next tutorial: Lambdas and Closures