Common Lisp the Language
2nd Edition

Of
course
the ability of the handler to usefully handle an exceptional
situation is related to the quality of the information it is provided. For
example
if all errors were signaled by
(error "some format string")
then the only piece of information that would be accessible to the handler would be an object of type simple-error that had a slot containing the format string.
If this were done string-equal would be the preferred way to tell one error from another and it would be very hard to allow flexibility in the presentation of error messages because existing handlers would tend to be broken by even tiny variations in the wording of an error message. This phenomenon has been the major failing of most error systems previously available in Lisp. It is fundamentally important to decouple the error message string (the human interface) from the objects that formally represent the error state (the program interface). We therefore have the notion of typed conditions and of formal operations on those conditions that make them inspectable in a structured way.
This object-oriented approach to condition handling has the following important advantages over a text-based approach:
Some condition types are defined by this document but the set of condition types is extensible using define-condition. Common Lisp condition types are in fact CLOS classes and condition objects are ordinary CLOS objects; define-condition merely provides an abstract interface that is a bit more convenient than defclass for defining conditions.
Here as an example we define a two-argument function called divide that is patterned after the / function but does some stylized error checking:
(defun divide (numerator denominator) (cond ((or (not (numberp numerator)) (not (numberp denominator))) (error "(DIVIDE '~S '~S) - Bad arguments." numerator denominator)) ((zerop denominator) (error 'division-by-zero :operator 'divide :operands (list numerator denominator))) (t ...)))
Note that in the first clause we have used error with a string argument and in the second clause we have named a particular condition type division-by-zero. In the case of a string argument the condition type that will be signaled is simple-error.
The particular kind of error that is signaled may be important
in cases where handlers are active. For example
simple-error inherits
from type error
which in turn inherits from type condition. On the
other hand
division-by-zero inherits from arithmetic-error
which
inherits from error
which inherits from condition. So if a handler
existed for arithmetic-error while a division-by-zero condition was
signaled
that handler would be tried; however
if a simple-error
condition were signaled in the same context
the handler for type
arithmetic-error would not be tried.