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.