Blocks

A block is a piece of code you can pass around and call later. Every brace-delimited { … } is a block. Blocks are what control-flow forms like if run, what consumers like each and select invoke per element, and what a def binds to a name.

A block's body is a sequence of statements separated by newlines or semicolons. Each statement is a command call.

{ do "wave" }
{ do "smile" ; do "bow" }

Parameters

When a block needs arguments, declare the parameter names in angle brackets immediately after the opening brace. The parameters bind the arguments by position, and the body reads them by name.

{ <x> [+ $x 1] }              # one parameter
{ <x y> [+ $x $y] }           # two parameters
{ <drink> do "say one $drink" }

Whitespace and newlines inside <...> and between > and the body do not matter. For a long body, the idiom is to put the signature on the opening line:

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

Parameter names must be plain words (not <5> or <true>, which are reserved literals) and must be distinct.

The rest parameter ...

The last parameter may be prefixed with ..., making the block accept any number of trailing arguments. The rest name binds an iterable over those extra arguments, in call order, each kept as a separate element.

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

Only one rest parameter is allowed and it must come last. Because each argument is one element, the rest iterable is not a word iterable: an argument that contains spaces stays a single element. (Contrast $args, the whitespace-split command line.) When no extra arguments are passed, the rest binds an empty iterable, never null[count $rest] is 0.

How many arguments

The declared parameters are a strict minimum: calling a block with fewer arguments is a run-time error. Extra arguments are dropped (or collected by a rest parameter). A parameter-less { body } ignores any arguments it is given. The caller decides how many arguments to pass — if passes none, each passes one per element — so a block handed to if may not declare a required parameter.

Returned values

By default, a block will return the value of the last statement that executes. Because every statement is a command call, that last statement must itself be a value-producing call — a [...] substitution or a query command — for the block to yield a useful value:

def inc { <x> [+ $x 1] }      # yields x + 1

To return a value early, or to make the intent explicit, use return:

def classify { <c>
  if [ge [level $c] 20] { return [upper "elite"] }
  return [upper "common"]
}

A plain variable or literal alone is not a value statement — a line that is just $n or 'elite' is read as a command call and fails. Wrap it: write return $n, or [upper "elite"], rather than a bare $n.

An empty body — {}, { <> }, or { <x> } with no statements — yields null, and so does bare return.

Examples

after command (say) {
  each [words "north east south west"] { <dir>
    do "say I could go $dir."
  }
}

Runs the one-parameter block once per word.

def inc { <x> [+ $x 1] }

after command (say) {
  do "say [inc 4]"
}

A named block used as a function; [inc 4] yields 5, so the mob says "5."

See also