Common Lisp the Language, 2nd Edition
Next: Restarts
Up: Survey of Concepts
Previous: Handling
Conditions
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.
Next: Restarts
Up: Survey of Concepts
Previous: Handling
Conditions
AI.Repository@cs.cmu.edu