Common Lisp constructs are described not only in terms of their behavior in situations during which they are intended to be used (see the “Description” part of each operator specification), but in all other situations (see the “Exceptional Situations” part of each operator specification).
A situation is the evaluation of an expression in a specific context.
A condition is an object that
represents a specific situation that has been detected.
Conditions are generalized instances of the class condition
.
A hierarchy of condition classes is defined in Common Lisp.
A condition has slots that contain data
relevant to the situation that the condition represents.
An error is a situation in which normal program execution cannot continue correctly without some form of intervention (either interactively by the user or under program control). Not all errors are detected. When an error goes undetected, the effects can be implementation-dependent, implementation-defined, unspecified, or undefined. See Section 1.4 (Definitions). All detected errors can be represented by conditions, but not all conditions represent errors.
Signaling is the process by which a condition can alter
the flow of control in a program by raising the
condition which can then be handled. The functions
error
, cerror
, signal
, and
warn
are used to signal conditions.
The process of signaling involves the selection and invocation of a handler from a set of active handlers. A handler is a function of one argument (the condition) that is invoked to handle a condition. Each handler is associated with a condition type, and a handler will be invoked only on a condition of the handler's associated type.
Active handlers are established dynamically
(see handler-bind
or handler-case
).
Handlers are invoked in a dynamic environment
equivalent to that of the signaler,
except that the set of active handlers
is bound in such a way as to include only those that were active
at the time the handler being invoked was established.
Signaling a condition has no side-effect on the condition,
and there is no dynamic state contained in a condition.
If a handler is invoked, it can address the situation in one of three ways:
It can decline to handle the condition. It does this by
simply returning rather than transferring control.
When this happens, any values returned by the handler are
ignored and the next most recently established handler is invoked.
If there is no such handler and the signaling function is error
or cerror
, the debugger is entered in the
dynamic environment of the signaler. If there is no such
handler and the signaling function is either signal
or
warn
, the signaling function simply returns nil
.
It can handle the condition by performing a non-local
transfer of control. This can be done either primitively by using
go
, return
, throw
or more
abstractly by using a function such as abort
or
invoke-restart
.
It can put off a decision about whether to handle or decline, by any of a number of actions, but most commonly by signaling another condition, resignaling the same condition, or forcing entry into the debugger.