Chapter 7
Conditions
Signalers, Conditions, and Handlers
A condition is an object used to locate and provide information to a handler. A condition
represents a situation that needs to be handled. Examples
are errors, warnings, and attempts
to recover from errors. All conditions are instances
of <condition>
. Several subclasses
of <condition>
are provided for additional behavior. These are described
in Conditions
on page 244.
A handler is a function for handling conditions of a particular
type. Handlers may be installed dynamically with the local
declaration let handler
, and with
the exception
clause of the block
statement. Dynamically installed handlers are active for the duration of the execution of a
body. More recently installed handlers take precedence over less recently installed
handlers. If no dynamically installed handler handles a condition, the generic
function default-handler
is
called. default-handler
has predefined methods and may also have
program-defined methods.
Signaling is the mechanism for locating the most recently installed handler for a
condition. The basic mechanism for signaling is the
function signal
. Several functions built
on signal
are provided for additional behavior. These are described
in Signaling Conditions
on page
357.
When a condition is signaled, the condition facility locates the most recently installed applicable handler and calls it. An applicable handler is one that matches the signaled condition by type and by an optional test function associated with the handler. The condition system is simply a way for a signaler and a handler to be introduced to each other. Once they have met, they communicate through an ordinary function call. The condition object is the argument to that call.
Like any function, the called handler either returns some values or takes a nonlocal exit. Either way, the handler has handled the condition, and the act of signaling is completed.
A handler also has the option of declining to handle the condition by passing control to the next applicable handler. It does this by tail recursively calling a next-handler function which it received as an argument. The next-handler function calls the next most recently installed applicable handler with appropriate arguments. This is analogous to the next-method function used in methods of generic functions.
(The call to next-handler is described as tail-recursive to ensure that all values returned by the call are returned by the handler. Not returning all the values could interfere with the condition's recovery protocol. A handler that really knows what it is doing could use a non-tail-recursive call, but anything that knows what it's doing in this situation is probably unmodular. Note that a handler might not know the full recovery protocol, because the condition might be a subtype of the handler's expected type.)
Every signaled condition is handled, because the system ensures that there is always an applicable default handler that does not decline.
If a handler handles a condition by returning (rather than by taking a nonlocal exit) the
values it returns are returned by signal
.