Conditions and Handlers
36.1 Signaling and Handling Errors
(error "Something went wrong: ~a" 42) ; signals a SIMPLE-ERROR
(warn "Low disk space") ; signals a WARNING (prints, continues)
(signal 'my-condition) ; signals without requiring handling
(assert (> 1 0) () "Math is broken") ; assertion (offers a continue restart)
(check-type x integer) ; type assertion with a store-value restart
;; handler-case: like try/catch (unwinds the stack to the handler)
(handler-case (/ 10 0)
(division-by-zero (c)
(format nil "Caught: ~a" c))
(error (c)
(format nil "Other error: ~a" c)))
(handler-case (parse-integer "abc")
(parse-error () :invalid)
(:no-error (value position) ; runs when no error occurred
(declare (ignore position))
(list :ok value)))
;; ignore-errors: return NIL and the condition on error
(ignore-errors (/ 1 0)) ; NIL, #<DIVISION-BY-ZERO>36.2 Defining Condition Types
Standard condition types condition → serious-condition → error
simple-error, type-error, program-error, control-error
arithmetic-error → division-by-zero, floating-point-overflow
cell-error → unbound-variable, undefined-function, unbound-slot
file-error, stream-error → end-of-file, parse-error, reader-error
warning → style-warning, simple-warning Out of memory, stack exhaustion
(define-condition bank-error (error) ())
(define-condition insufficient-funds (bank-error)
((balance :initarg :balance :reader balance)
(requested :initarg :requested :reader requested))
(:report (lambda (c stream)
(format stream "Insufficient funds: balance ~a, requested ~a"
(balance c) (requested c)))))
(defun withdraw* (balance amount)
(when (> amount balance)
(error 'insufficient-funds :balance balance :requested amount))
(- balance amount))
(handler-case (withdraw* 50 100)
(insufficient-funds (c)
(format t "~a (short by ~a)~%" c (- (requested c) (balance c)))))
;; Insufficient funds: balance 50, requested 100 (short by 50)36.3 handler-bind: Handling Without Unwinding
;; handler-bind runs the handler AT THE POINT OF THE SIGNAL; the stack is still intact.
;; The handler may: decline (return normally → the search continues), unwind (non-local exit),
;; or invoke a restart (Module 37).
(handler-bind ((warning (lambda (c)
(format t "~&Logged warning: ~a~%" c)
(muffle-warning c)))) ; invoke the MUFFLE-WARNING restart
(warn "deprecated function used")
:continued) ; :CONTINUED
(handler-case ; outer: unwinds and recovers
(handler-bind ((error (lambda (c) ; inner: runs first, logs, then declines
(format *error-output* "~&Error logged: ~a~%" c))))
(error "boom"))
(error () :recovered)) ; → :RECOVERED (after the log line)