11.2. Apply reflection pattern

The APPLY module provides the apply macro for iterating over struct, tuple, and variant fields at compile time. Each field is visited with its name and a reference to its value, enabling generic per-field operations like serialization, printing, and validation.

All functions and symbols are in “apply” module, use require to get access to it.

require daslib/apply

Example:

require daslib/apply

struct Foo {
    a : int
    b : float
    c : string
}

[export]
def main() {
    var foo = Foo(a = 42, b = 3.14, c = "hello")
    apply(foo) $(name, field) {
        print("{name} = {field}\n")
    }
}
// output:
// a = 42
// b = 3.14
// c = hello

When the block has no function-escaping return, it runs inline once per field — no helper function and no per-field block invoke — so it is cheap enough for hot paths like serialization. A block that uses return to skip a field falls back transparently to a generated per-field helper, where return keeps its original block-local “skip this field” meaning; nothing the caller writes changes. apply_imm is a struct-only, slightly faster variant (it aliases the block params rather than binding reference locals); use it for hot struct field walks and apply for tuples, variants, a side-effecting source value, or a block that uses return (apply_imm always inlines, so it cannot accept one).

See also

Compile-Time Field Iteration with apply — comprehensive tutorial covering structs, tuples, variants, static_if dispatch, mutation, generic describe, and the 3-argument annotation form.

11.2.1. Call macros

apply_imm

Struct-only, faster sibling of apply for a hot field walk (e.g. a serialization materializer).

apply

Visits every field of a struct, tuple, or variant with a per-field block. The block is $(name, field)name is the field-name string (a compile-time constant, so static_if (name == "...") folds) and field is a reference to the field value (read or mutate; writes propagate to the source). A struct may use a third annotations param receiving array<tuple<name:string; data:RttiValue>> per field. A variant runs only its active arm.