Skip to main content

handler-case

handler-case Macro

Syntax:

handler-case expression [[ {↓error-clause}* | ↓no-error-clause ]] → {result}*

clause::=↓error-clause | ↓no-error-clause

error-clause::=(typespec ([var]) {declaration}* {form}*)

no-error-clause::=(:no-error lambda-list {declaration}* {form}*)

Arguments and Values:

expression—a form.

typespec—a type specifier.

handler-case

var—a variable name.

lambda-list—an ordinary lambda list.

declaration—a declare expression; not evaluated.

form—a form.

results—In the normal situation, the values returned are those that result from the evaluation of expression; in the exceptional situation when control is transferred to a clause, the value of the last form in that clause is returned.

Description:

handler-case executes expression in a dynamic environment where various handlers are active. Each error-clause specifies how to handle a condition matching the indicated typespec. A no-error-clause allows the specification of a particular action if control returns normally.

If a condition is signaled for which there is an appropriate error-clause during the execution of expression (i.e., one for which (typep conditiontypespec) returns true) and if there is no intervening handler for a condition of that type, then control is transferred to the body of the relevant error-clause. In this case, the dynamic state is unwound appropriately (so that the handlers established around the expression are no longer active), and var is bound to the condition that had been signaled. If more than one case is provided, those cases are made accessible in parallel. That is, in

(handler-case form

(typespec1 (var1) form1)

(typespec2 (var2) form2))

if the first clause (containing form1) has been selected, the handler for the second is no longer visible (or vice versa).

The clauses are searched sequentially from top to bottom. If there is type overlap between typespecs, the earlier of the clauses is selected.

If var is not needed, it can be omitted. That is, a clause such as:

(*typespec* (*var*) (declare (ignore *var*)) form)

can be written (*typespec* () form).

If there are no forms in a selected clause, the case, and therefore handler-case, returns nil. If execution of expression returns normally and no no-error-clause exists, the values returned by expression are returned by handler-case. If execution of expression returns normally and a no-error-clause does exist, the values returned are used as arguments to the function described by constructing (lambda lambda-list {form}*) from the no-error-clause, and the values of that function call are returned by handler-case. The handlers which were established around the expression are no longer active at the time of this call.

handler-case

Examples:

(defun assess-condition (condition) 
(handler-case (signal condition)
(warning () "Lots of smoke, but no fire.")
((or arithmetic-error control-error cell-error stream-error)
(condition)
(format nil "~S looks especially bad." condition))
(serious-condition (condition)
(format nil "~S looks serious." condition))
(condition () "Hardly worth mentioning.")))
→ ASSESS-CONDITION
(assess-condition (make-condition ’stream-error :stream \*terminal-io\*))"#<STREAM-ERROR 12352256> looks especially bad."
(define-condition random-condition (condition) ()
(:report (lambda (condition stream)
(declare (ignore condition))
(princ "Yow" stream))))
→ RANDOM-CONDITION
(assess-condition (make-condition ’random-condition))
"Hardly worth mentioning."

See Also:

handler-bind, ignore-errors, Section 9.1 (Condition System Concepts)

Notes:

(handler-case form 
(*type1* (*var1*) . *body1*)
(*type2* (*var2*) . *body2*) ...)

is approximately equivalent to:

(block #1=#:g0001 
(let ((#2=#:g0002 nil))
(tagbody
(handler-bind ((*type1* #’(lambda (temp)
(setq #1# temp)
(go #3=#:g0003)))
(*type2* #’(lambda (temp)
(setq #2# temp)
(go #4=#:g0004))) ...)
(return-from #1# form))

#3# (return-from #1# (let ((*var1* #2#)) . *body1*))

#4# (return-from #1# (let ((*var2* #2#)) . *body2*)) ...)))

(handler-case form
(*type1 (var1)* . *body1*)
...
(:no-error (*varN-1 varN-2* ...) . *bodyN*))

is approximately equivalent to:

(block #1=#:error-return 
(multiple-value-call #’(lambda (*varN-1 varN-2* ...) . *bodyN*)
(block #2=#:normal-return
(return-from #1#
(handler-case (return-from #2# form)
(*type1* (*var1*) . *body1*) ...)))))

Expanded Reference: handler-case

Basic Error Handling

handler-case evaluates an expression and, if a condition of a matching type is signaled, transfers control to the corresponding clause. Unlike handler-bind, the stack is unwound before the clause body executes.

(handler-case
(error "Something went wrong")
(error (c)
(format nil "Caught: ~A" c)))

=> "Caught: Something went wrong"

Handling Different Condition Types

Multiple clauses can handle different condition types. Clauses are searched sequentially from top to bottom, so more specific types should come first.

(handler-case
(error "A simple error")
(simple-error (c)
(format nil "Simple error: ~A" c))
(error (c)
(format nil "General error: ~A" c)))

=> "Simple error: A simple error"

Ignoring the Condition Variable

If you do not need to reference the condition object, you can omit the variable by using an empty lambda list ().

(handler-case
(/ 1 0)
(division-by-zero ()
:infinity))

=> :INFINITY

Normal Return Values

When no condition is signaled, handler-case returns the values of the expression.

(handler-case
(values 1 2 3)
(error () :oops))
=> 1
=> 2
=> 3

The :no-error Clause

A :no-error clause is executed when the expression returns normally. Its lambda list receives the values returned by the expression.

(handler-case
(values 10 20)
(error (c) (format nil "Error: ~A" c))
(:no-error (a b)
(+ a b)))

=> 30

Practical Example: Safe Division

A function that catches division-by-zero and returns a default value.

(defun safe-divide (a b &optional (default 0))
(handler-case (/ a b)
(division-by-zero () default)
(type-error (c)
(format nil "Type error: ~A" c))))

(safe-divide 10 3)

=> 10/3
(safe-divide 10 0)

=> 0
(safe-divide 10 0 :infinity)

=> :INFINITY