BlockA closure: code plus its captured environment. Written as a literal { ... }, with parameters as { |x y| ... }. Run one with value / value: / valueWithArgs:, loop with whileDo:, handle errors with catch:. Inside a block, ^ returns from the block itself and ^^ returns from the enclosing method.
Blocks as match patterns and as loop conditions.
Identity: true only for the very same block object -- two textually identical literals are not equal.
var b = { 1 }; b == b "* -> true { 1 } == { 1 } "* -> false
The declared parameter names, as a List of Strings.
{ |a b| a + b }.args "* -> #(a b)
How many parameters the block declares.
{ |a b| a + b }.arity "* -> 2
The variadic multi-catch: writing { ... }.catch:{ |e:A| ... } catch:{ |e:B| ... } folds the run of catch: keywords into one List of handlers. They are tried in source order, FIRST match wins -- write them most- to least-specific and put any catch-all |e| last.
{ 'x'.throw }.catch:{ |e: IoError| 'io' } catch:{ |e| 'other' } "* -> other
The multi-catch form of catch:finally:: several typed handlers (tried in source order, first match wins) plus a finally that always runs.
Run the block; if it throws, run the handler when the handler parameter's declared type matches the exception (an untyped |e| or zero-parameter handler catches everything), else re-raise to an enclosing catch:. Answers the protected block's value, or the handler's. Cancellation and Runtime.exit: are never caught.
{ 1 / 0 }.catch:{ |e: ArithmeticError| 'caught' } "* -> caught { 'boom'.throw }.catch:{ |e| e } "* -> boom
As catch:, but the finally block ALWAYS runs -- on success, on a caught or re-raised throw, and on cancellation. An error thrown by finally itself overrides the result it runs after.
{ 42 }.catch:{ |e| 0 } finally:{ 'cleanup'.print } "* prints cleanup -> 42
The block's source text, or nil when no source info was recorded.
{ 1 }.code "* -> { 1 }
Run the block, then ALWAYS run the cleanup — on success, on a throw (which re-raises unchanged after the cleanup), on cancellation, and on the way out of a non-local return. An error thrown by the cleanup itself overrides a normal result but never masks a cancellation.
var log = #(); { { 'boom'.throw }.finally:{ log.add:'cleaned' } }.catch:{ |e| log.add:e }; log "* -> #(cleaned boom)
The block's name as a Symbol -- a method body carries its selector -- or nil for an anonymous literal.
Assert the block's shape can be shipped to a worker (docs/internal/CONCURRENCY_ARCH.md): raises unless it is free of write-captures, ^^, self/@field access, guards, and class/method definition; answers the block. The parallel combinators check it on every path -- serial fallbacks included -- so refusals don't depend on input size. (Whether the captured VALUES are portable is checked only when actually shipping.)
Where the block was defined: #( filename line column ) -- line 1-indexed, column 0-indexed -- or nil when the block carries no source info. The test reporter uses it to point a failed assertion at its source.
Run the block with no arguments; answers its last expression (or the value a ^ returned).
{ 42 }.value "* -> 42
Run the block with one argument.
{ |x| x * 2 }.value:21 "* -> 42
Run the block with both an argument and an explicit self: a List first argument spreads as the parameter list, any other value passes as the single argument.
Run the block with a List of arguments -- the multi-parameter form (value: takes exactly one argument).
{ |a b| a + b }.valueWithArgs:#( 2 3 ) "* -> 5
Run a zero-parameter block with self bound to the argument, so self sends and the .foo shorthand read it.
{ .length }.valueWithSelf:'abc' "* -> 3
Hand one item to a block of either shape -- the combinator seam (each:, collect:, ... deliver items through it). A parameterless block gets the item as self (the { .name } shorthand); a parameterized block gets it as the argument, with self staying lexical.
{ |x| x + 1 }.valueWithSelfOrArg:2 "* -> 3 { .length }.valueWithSelfOrArg:'abc' "* -> 3
Loop while the receiver answers a defined value, passing each value to block — the idiom for draining a cursor or other yields-nil-when-done source.
var n = 0; var total = 0; { n = n + 1; (n < 4).if:{ n } }.whileDefinedDo:{ |v| total = total + v }; total "* -> 6
The while loop: re-evaluate the receiver before each pass and, while it answers true, run block.
var i = 0; { i < 3 }.whileDo:{ i = i + 1 }; i "* -> 3
A block used as a match pattern ({|n| n > 5} ~ x / case when:) runs as a predicate: the subject is passed as the argument and as self, so both {|n| ...} and { . ... } guard forms work.