Blocks

A block is a first-class callable code value (Types): every brace-delimited form { … } is a block. A block's body is a newline/semicolon-separated sequence of statements. A block bound to a name — by def, or as a builtin — is a function.

Block      = '{' [ ParamList ] Body '}' .
Body       = { Statement (newline | ';') } .
Statement  = CommandCall .                 # see Expressions
ParamList  = '<' { param } [ '...' param ] '>' .

Control-flow constructs, handlers, and ordinary callables all receive the same kind of value — a block — and differ only in how they invoke it (Expressions, Program initialization and execution).

Named-parameter blocks

{ <params> body } — one or more parameter names inside angle brackets, immediately after {. The parameters bind the arguments positionally; the body reads them by name.

{ <x> + $x 1 }
{ <x y> + $x $y }
{ <drink> do "say one $drink" }

Whitespace and newlines inside <...> and between > and the body are insignificant. The idiom for a long body is to put the signature on the opening line:

def calculate_damage { <attacker weapon target>
    ...body...
}

Rest parameter

The final parameter may be prefixed with ..., making the block variadic. The rest parameter binds an iterable over the trailing arguments (iterables) — the arguments beyond the declared parameters, in call order, each preserved as a distinct element. Only one rest parameter is allowed and it must be last.

{ <first ...others> ... }     # first arg named; the rest as an iterable
{ <...all> ... }              # fully variadic, zero or more args

The rest iterable is heterogeneous (an element may be of any type) and order-preserving. Because each argument is one element, it is not a word iterable: an argument whose value contains spaces stays a single element. (Contrast $args, the whitespace-split command line, which is a word iterable — Program initialization and execution.)

Being an ordinary iterable, it is consumed by the iterable consumers (Built-in functions) and may be traversed more than once. When the call passes no trailing arguments the rest parameter binds an empty iterable, never null: [count $rest] is 0.

Restrictions

Arity and calls

Declared arity is the number of non-rest parameters and is a strict minimum. A call with fewer arguments is a run-time error. Extra arguments are dropped (non-variadic) or collected into the rest iterable (variadic). Arguments bind to the parameters positionally; a parameter-less { body } ignores any arguments it is called with.

The caller decides how many arguments a block receives: some callers pass zero (e.g. if branches), others pass one per element (e.g. each). The individual callers are documented in Expressions and Built-in functions. Handler argument binding is specified in Program initialization and execution.

Compile-time arity check for zero-argument consumers

if and randomly invoke their branch blocks with zero arguments. A branch that is a block with declared arity ≥ 1 can never be satisfied, so it is rejected at compile time. The empty forms { <> body }, a pure rest { <...rest> body }, and a plain { body } accept zero arguments and are allowed.

Block value and return

A block's value is the value of its body's last evaluated statement, returned when control falls off the end.

{ <x> + $x 1 }      # returns x + 1
{ do "wave" }       # returns the result of the last statement

Special cases:

break, continue, and return propagate outward through enclosing constructs; the full rules are in Run-time.

Statement form

Every statement is a command call (Expressions) and produces a value; the body discards all but the last.