The condition system generalises exceptions. A condition is an object that describes a situation. Code signals it; the system finds a handler by looking through the active handler bindings, most recent first; the handler can decline (by returning), or transfer control out (by return-from, go or throw), or invoke a restart, a named way to carry on that code lower in the stack has offered. Because the handler runs before the stack is unwound, a restart can resume the signalling code where it was. Errors that are not handled enter the debugger.
Standard condition types
| Type | Parent | Signalled when |
|---|---|---|
condition | (root) | the base type of all conditions; not a subtype of standard-object necessarily |
warning | condition | a situation to report that is not an error; warn signals it |
style-warning | warning | code is correct but poor style (unused variable, undefined function at the end of a compilation unit) |
serious-condition | condition | something that needs the debugger if not handled |
error | serious-condition | an error |
storage-condition | serious-condition | out of memory or stack |
simple-condition | condition | carries a format control and arguments (simple-condition-format-control, simple-condition-format-arguments) |
simple-error, simple-warning | simple-condition and error or warning | made by error and warn with a string |
type-error, simple-type-error | error | wrong type (type-error-datum, type-error-expected-type) |
arithmetic-error | error | an arithmetic problem (arithmetic-error-operation, arithmetic-error-operands) |
division-by-zero | arithmetic-error | a division by zero |
floating-point-overflow, floating-point-underflow, floating-point-inexact, floating-point-invalid-operation | arithmetic-error | the corresponding floating-point exception |
cell-error | error | access to a named location (cell-error-name) |
unbound-variable, undefined-function, unbound-slot | cell-error | the variable, function or slot has no value (unbound-slot-instance) |
control-error | error | invalid transfer of control, such as a return-from to a block that has exited |
program-error | error | wrong program syntax or argument count |
package-error | error | a problem with packages (package-error-package) |
stream-error | error | a stream problem (stream-error-stream) |
end-of-file | stream-error | input ran out |
reader-error | parse-error and stream-error | the reader could not read |
parse-error | error | text could not be parsed (parse-namestring, reader-error) |
file-error | error | a file operation failed (file-error-pathname) |
print-not-readable | error | an object cannot be written readably (print-not-readable-object) |
Signalling
(signal condition)looks for handlers and returnsnilif none takes control. The argument is a condition, a condition type name with initargs, or a format control and arguments.(warn …)signals awarningand, if no handler takes control, prints it to*error-output*; it offers the restartmuffle-warning.(error …)signals a condition and if no handler takes control calls the debugger (invoke-debugger, which uses*debugger-hook*if set); it never returns normally.(cerror continue-control condition …)iserrorwith acontinuerestart (the first argument is its report).(assert …)and(check-type …)signal correctable errors;(break …)enters the debugger.make-conditionmakes one without signalling;*break-on-signals*makes every signal of a given type enter the debugger first, for tracing.
Handling
(handler-case (parse-integer "12x")
(parse-error (c)
(format t "bad number: ~a~%" c)
0)
(:no-error (n) n))
(handler-bind ((warning #'muffle-warning)
(error (lambda (c)
(format t "problem: ~a~%" c)
(invoke-restart 'use-value 0))))
(risky-computation))
(restart-case (process-file path)
(skip-file ()
:report "Skip this file."
nil)
(use-other-file (new)
:report "Process another file."
:interactive (lambda () (list (read)))
(process-file new)))
handler-case unwinds before running its clause; handler-bind runs the function at the point of the signal, so it can pick a restart.handler-case clauses take a type, a one-variable list (or an empty list) and a body, and the last may be (:no-error lambda-list …), which runs if the form returns normally. ignore-errors is (handler-case form (error (c) (values nil c))). Handlers run with the handler bindings that were active when the handler was established, so an error inside a handler is not handled by the same handler.
Restarts
| Name | Meaning |
|---|---|
abort | return to the top level; always available in the debugger. Both the restart name and a function (abort). |
continue | continue after a correctable error; established by cerror and assert |
muffle-warning | silence a warning |
store-value | give a value to store, offered by check-type, ccase, unbound-variable and others |
use-value | give a value to use instead, offered by undefined-function, unbound-variable, ecase and others |
The functions are invoke-restart, invoke-restart-interactively, find-restart, compute-restarts, restart-name, and the functions named after the restarts above, which find the restart and invoke it if it exists ((use-value 3)). with-simple-restart offers a restart that returns nil and t; restart-bind is the form under restart-case. The restart options are :report, :interactive and :test. with-condition-restarts tells the system which restarts belong with a condition.
define-condition
(define-condition file-format-error (error)
((path :initarg :path :reader error-path)
(line :initarg :line :initform nil :reader error-line))
(:report (lambda (c stream)
(format stream "~a: bad format~@[ at line ~d~]"
(error-path c) (error-line c))))
(:default-initargs :line nil)
(:documentation "A data file could not be parsed."))
:report (a string or a function of the condition and a stream), :default-initargs, :documentation. Slot options are as in defclass.Condition types are classes in many implementations, but the standard guarantees only that they work with make-condition, slot readers, typep, subtypep and the condition operators; make-instance on a condition type need not work, and slot-value on a condition is unspecified in the standard.