Common Lisp the Language, 2nd Edition

Next: Defining Conditions Up: Program Interface to Previous: Exhaustive Case Analysis

## 29.4.4. Handling Conditions

These macros allow a program to gain control when a condition is signaled.

[Macro]
`handler-case expression {(typespec ([var]) {form}*)}*`

Executes the given expression in a context where various specified handlers are active.

Each typespec may be any type specifier. If during the execution of the `expression` a condition is signaled for which there is an appropriate clause-that is, one for which `(typep condition 'typespec)` is true-and if there is no intervening handler for conditions of that type, then control is transferred to the body of the relevant clause (unwinding the dynamic state appropriately in the process) and the given variable `var` is bound to the condition that was signaled. If no such condition is signaled and the computation runs to completion, then the values resulting from the `expression` are returned by the `handler-case` form.

If more than one case is provided, those cases are made accessible in parallel. That is, in

    (handler-case expression
      (type1 (var1) form1)
      (type2 (var2) form2))

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

The cases are searched sequentially from top to bottom. If a signaled condition matches more than one case (possible if there is type overlap) the earlier of the two cases will be selected.

If the variable var is not needed, it may be omitted. That is, a clause such as

    (type (var) (declare (ignore var)) form)

may be written using the following shorthand notation:

    (type () form)

If there are no forms in a selected case, the case returns `nil`. Note that

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

is approximately equivalent to

    (block #1=#:block-1
      (let (#2=#:var-2)
        (tagbody
          (handler-bind ((type1 ¯#'(lambda (temp)
    		    (setq #2# temp)
    		    (go #3=#:tag-3)))
                         (type2 ¯#'(lambda (temp)
    		    (setq #2# temp)
    		    (go #4=#:tag-4)))
                         ...)
            (return-from #1# expression))
          #3# (return-from #1# (let ((var1 #2#)) . body1))
          #4# (return-from #1# (let ((var2 #2#)) . body2))
          ...)))

[Note the use of ``gensyms'' such as `#:block-1` as block names, variables, and `tagbody` tags in this example, and the use of `#n=` and `#n#` read-macro syntax to indicate that the very same gensym appears in multiple places.-GLS]

As a special case, the typespec can also be the symbol `:no-error` in the last clause. If it is, it designates a clause that will take control if the expression returns normally. In that case, a completely general lambda-list may follow the symbol `:no-error`, and the arguments to which the lambda-list parameters are bound are like those for `multiple-value-call` on the return value of the expression. For example,

    (handler-case expression
      (type1 (var1) . body1)
      (type2 (var2) . body2)
      ...
      (typen (varn) . bodyn)
      (:no-error (nvar1 nvar2 ... nvarm) . nbody))

is approximately equivalent to

    (block #1=#:error-return
      (multiple-value-call #'(lambda (nvar1 nvar2 ... nvarm) . nbody)
        (block #2=#:normal-return
          (return-from #1#
            (handler-case (return-from #2# expression)
              (type1 (var1) . body1)
              (type2 (var2) . body2)
              ...
              (typen (varn) . bodyn))))))

Examples of the use of `handler-case`:

    (handler-case (/ x y)
      (division-by-zero () nil))

    (handler-case (open *the-file* :direction :input)
      (file-error (condition) (format t "~&Fooey: ~A~%" condition)))

    (handler-case (some-user-function)
      (file-error (condition) condition)
      (division-by-zero () 0)
      ((or unbound-variable undefined-function) () 'unbound))

    (handler-case (intern x y)
      (error (condition) condition)
      (:no-error (symbol status)
        (declare (ignore symbol))
        status))

[Macro]
`ignore-errors {form}*`

Executes its body in a context that handles conditions of type `error` by returning control to this form. If no such condition is signaled, any values returned by the last form are returned by `ignore-errors`. Otherwise, two values are returned: `nil` and the `error` condition that was signaled.

`ignore-errors` could be defined by

    (defmacro ignore-errors (&body forms)
      `(handler-case (progn ,@forms)
         (error (c) (values nil c)))

[Macro]
`handler-bind ({(typespec handler)}*) {form}*`

Executes body in a dynamic context where the given handler bindings are in effect. Each typespec may be any type specifier. Each handler form should evaluate to a function to be used to handle conditions of the given type(s) during execution of the forms. This function should take a single argument, the condition being signaled.

If more than one binding is specified, the bindings are searched sequentially from top to bottom in search of a match (by visual analogy with `typecase`). If an appropriate typespec is found, the associated handler is run in a context where none of the handler bindings are visible (to avoid recursive errors). For example, in the case of

    (handler-bind ((unbound-variable #'(lambda ...))
                   (error #'(lambda ...)))
      ...)

if an unbound variable error is signaled in the body (and not handled by an intervening handler), the first function will be called. If any other kind of error is signaled, the second function will be called. In either case, neither handler will be active while executing the code in the associated function.

Next: Defining Conditions Up: Program Interface to Previous: Exhaustive Case Analysis