Conditions & Restarts
Atomo uses a condition system very similar to Common Lisp's.
Signals
signal: v → @ok
Sends a value to all bound handlers, nearest-first.
Handlers
action bind: handlers → any | action is-a?: Block | handlers is-a?: Block
Performs action
, with a handler for all signals matched in handlers
block. Returns the result of action
.
The contents of handlers
should be Association
expressions, e.g. pattern -> responder
, where pattern
is a match on the signal value, and responder
is either a Block
(which will be called with the signal value itself as an argument) or an expression to be evaluated in response to the signal.
Example:
> { signal: @foo } bind: { @foo -> "fooed!" print } fooed! @ok > { signal: @(bar: 42) } bind: { @(bar: x) -> @(fooed: x) print } @(fooed: 42) @ok > { error: @uh-oh } bind: { Error -> { e | @(got-error: e) print } } @(got-error: <error @uh-oh>) ERROR: <error @uh-oh>
A responder
may often invoke restart:
or restart:with:
, which is the only way they can affect the return value of action
.
After a handler responds to a signal, the signal continues outward to the next recently bound handler:
action with-restarts: restarts → any | action is-a?: Block | restarts is-a?: Block
Call action
, binding the restarts described by restarts
. These restarts, when invoked, will replace the result of action
.
The contents of restarts
should be Association
expressions, e.g. name -> expression
, where name
is the name for the restart, and expression
is the action to be performed when the restart is invoked.
Example:
> { { x } with-restarts: { ignore -> @ok } } bind: { Error -> restart: 'ignore } @ok
action with-restarts: restarts bind: handlers → any | action is-a?: Block | restarts is-a?: Block | handlers is-a?: Block
Trivial macro which just expands to with-restarts:
and bind:
.
restart: name with: (... args) → any | name is-a?: Expression
Invokes restart name
with args
passed to the block.
Traditional Exceptions
These methods are specific to errors, and provide a system similar to that of traditional exception handling. They are defined in terms of the more general condition system.
action catch: recover → any | action is-a?: Block | recover responds-to?: @call:
Execute action call
, catching any errors and passing them to recover
for handling.
Yields the result of action
or recover
.
action catch: recover ensuring: cleanup → any | [action, recover, cleanup] all?: @(is-a?: Block)
Execute action call
, catching any errors and passing them to recover
for handling, and ensuring that cleanup
is called after the action is executed.
Yields the result of action
or recover
.
action handle: branches → any | action is-a?: Block | branches is-a?: Block
Similar to catch:
, but branches
is a block containing exception patterns bound to the action to take if they're thrown. If none of the exceptions match any of the patterns, the exception is re-thrown.
action ensuring: cleanup → any | action is-a?: Block | cleanup is-a?: Block
Execute action call
, ensuring that cleanup
is called after the action is executed.
Yields the result of action
.