Common Lisp the Language, 2nd Edition
![]()
Next: Creating Conditions
Up: Program Interface to
Previous: Handling
Conditions

[The contents of this section are still a subject of some debate within
X3J13. The reader may wish to take this section with a grain of salt,
two aspirin tablets, and call a hacker in the morning.-GLS]
[Macro]
define-condition name ({parent-type}*)
[({slot-specifier}*) {option}*]
Defines a new condition type called name, which is a subtype of each given parent-type. Except as otherwise noted, the arguments are not evaluated.
Objects of this condition type will have all of the indicated slots, plus any additional slots inherited from the parent types (its superclasses). If the slots list is omitted, the empty list is assumed.
A slot must have the form
slot-specifier ::= slot-name | (slot-name [[?slot-option]])
For the syntax of a slot-option, see defclass.
The slots of a condition object are normal CLOS slots. Note that
with-slots may be used instead of accessor functions to
access slots of a condition object.
make-condition will accept keywords (in the keyword
package) with the print name of any of the designated slots, and will
initialize the corresponding slots in conditions it creates.
Accessors are created according to the same rules as used by
defclass.
The valid options are as follows:
(:documentationdoc-string)
The doc-string should be either nil or a string
that describes the purpose of the condition type. If this option is
omitted, nil is assumed. Calling
(documentation 'name'type)
will retrieve this information.
(:reportexp)
If exp is not a literal string, it must be a suitable argument
to the function special form. The expression
(functionexp) will be
evaluated in the current lexical environment. It should produce a
function of two arguments, a condition and a stream, that prints on the
stream a description of the condition. This function is called whenever
the condition is printed while *print-escape* is
nil.
If exp is a literal string, it is shorthand for
(lambda (c s)
(declare (ignore c))
(write-string exp s))
[That is, a function is provided that will simply write the given string literally to the stream, regardless of the particular condition object supplied.-GLS]
The :report option is processed after the new
condition type has been defined, so use of the slot accessors within the
report function is permitted. If this option is not specified,
information about how to report this type of condition will be inherited
from the parent-type.
[X3J13 voted in March 1989 (ZLOS-CONDITIONS) to integrate the
Condition System and the Object System. In the original Condition System
proposal, define-condition allowed only one
parent-type (the inheritance structure was a simple hierarchy).
Slot descriptions were much simpler, even simpler than those for
defstruct:
slot ::= slot-name | (slot-name) | (slot-name default-value)
Similarly, define-condition allowed a
:conc-name option similar to that of
defstruct:
(:conc-namesymbol-or-string)
Not now part of Common Lisp. As with
defstruct, this sets up automatic prefixing of the names of
slot accessors. Also as in defstruct, the default behavior
is to use the name of the new type, name, followed by a hyphen.
(Generated names are interned in the package that is current at the time
that the define-condition is processed).
One consequence of the vote was to make define-condition
slot descriptions like those of defclass.-GLS]
Here are some examples of the use of
define-condition.
The following form defines a condition of type
peg/hole-mismatch that inherits from a condition type
called blocks-world-error:
(define-condition peg/hole-mismatch (blocks-world-error)
(peg-shape hole-shape)
(:report
(lambda (condition stream)
(with-slots (peg-shape hole-shape) condition
(format stream "A ~A peg cannot go in a ~A hole."
peg-shape hole-shape))))
The new type has slots peg-shape and
hole-shape, so make-condition will accept
:peg-shape and :hole-shape keywords. The
with-slots macro may be used to access the
peg-shape and hole-shape slots, as illustrated
in the :report information.
Here is another example. This defines a condition called
machine-error that inherits from error:
(define-condition machine-error (error)
((machine-name
:reader machine-error-machine-name))
(:report (lambda (condition stream)
(format stream "There is a problem with ~A."
(machine-error-machine-name condition)))))
Building on this definition, we can define a new error condition that
is a subtype of machine-error for use when machines are not
available:
(define-condition machine-not-available-error (machine-error) ()
(:report (lambda (condition stream)
(format stream "The machine ~A is not available."
(machine-error-machine-name condition)))))
We may now define a still more specific condition, built upon
machine-not-available-error, that provides a default for
machine-name but does not provide any new slots or report
information. It just gives the machine-name slot a default
initialization:
(define-condition my-favorite-machine-not-available-error
(machine-not-available-error)
((machine-name :initform "MC.LCS.MIT.EDU")))
Note that since no :report clause was given, the
information inherited from machine-not-available-error will
be used to report this type of condition.

![]()
Next: Creating Conditions
Up: Program Interface to
Previous: Handling
Conditions
AI.Repository@cs.cmu.edu