Common Lisp the Language, 2nd Edition

Next: Macros Up: Control Structure Previous: Rules Governing the

# 7.11. Dynamic Non-Local Exits

Common Lisp provides a facility for exiting from a complex process in a non-local, dynamically scoped manner. There are two classes of special forms for this purpose, called catch forms and throw forms, or simply catches and throws. A catch form evaluates some subforms in such a way that, if a throw form is executed during such evaluation, the evaluation is aborted at that point and the catch form immediately returns a value specified by the throw. Unlike `block` and `return` (section 7.7), which allow for exiting a `block` form from any point lexically within the body of the `block`, the catch/throw mechanism works even if the throw form is not textually within the body of the catch form. The throw need only occur within the extent (time span) of the evaluation of the body of the catch. This is analogous to the distinction between dynamically bound (special) variables and lexically bound (local) variables.

[Special Form]
`catch` `tag` `{form}*`

The `catch` special form serves as a target for transfer of control by `throw`. The form tag is evaluated first to produce an object that names the catch; it may be any Lisp object. A catcher is then established with the object as the tag. The forms are evaluated as an implicit `progn`, and the results of the last form are returned, except that if during the evaluation of the forms a throw should be executed such that the tag of the throw matches (is `eq` to) the tag of the `catch` and the catcher is the most recent outstanding catcher with that tag, then the evaluation of the forms is aborted and the results specified by the throw are immediately returned from the `catch` expression. The catcher established by the `catch` expression is disestablished just before the results are returned.

The tag is used to match throws with catches. `(catch 'foo form)` will catch a `(throw 'foo form)` but not a `(throw 'bar form)`. It is an error if `throw` is done when there is no suitable `catch` ready to catch it.

Catch tags are compared using `eq`, not `eql`; therefore numbers and characters should not be used as catch tags.

Compatibility note: The name `catch` comes from MacLisp, but the syntax of `catch` in Common Lisp is different. The MacLisp syntax was `(catch form tag)`, where the tag was not evaluated.

[Special Form]
`unwind-protect` `protected-form` `{cleanup-form}*`

Sometimes it is necessary to evaluate a form and make sure that certain side effects take place after the form is evaluated; a typical example is

    (progn (start-motor)
           (drill-hole)
           (stop-motor))

The non-local exit facility of Common Lisp creates a situation in which the above code won't work, however: if `drill-hole` should do a throw to a catch that is outside of the `progn` form (perhaps because the drill bit broke), then `(stop-motor)` will never be evaluated (and the motor will presumably be left running). This is particularly likely if `drill-hole` causes a Lisp error and the user tells the error-handler to give up and abort the computation. (A possibly more practical example might be

    (prog2 (open-a-file)
           (process-file)
           (close-the-file))

where it is desired always to close the file when the computation is terminated for whatever reason. This case is so important that Common Lisp provides the special form `with-open-file` for this purpose.)

In order to allow the example hole-drilling program to work, it can be rewritten using `unwind-protect` as follows:

    ;; Stop the motor no matter what (even if it failed to start).

    (unwind-protect
      (progn (start-motor)
             (drill-hole))
      (stop-motor))

If `drill-hole` does a throw that attempts to quit out of the `unwind-protect`, then `(stop-motor)` will be executed.

This example assumes that it is correct to call `stop-motor` even if the motor has not yet been started. Remember that an error or interrupt may cause an exit even before any initialization forms have been executed. Any state restoration code should operate correctly no matter where in the protected code an exit occurred. For example, the following code is not correct:

    (unwind-protect
      (progn (incf *access-count*)
             (perform-access))
      (decf *access-count*))

If an exit occurs before completion of the `incf` operation the `decf` operation will be executed anyway, resulting in an incorrect value for `*access-count*`. The correct way to code this is as follows:

    (let ((old-count *access-count*))
      (unwind-protect
        (progn (incf *access-count*)
               (perform-access))
        (setq *access-count* old-count)))

As a general rule, `unwind-protect` guarantees to execute the cleanup-forms before exiting, whether it terminates normally or is aborted by a throw of some kind. (If, however, an exit occurs during execution of the cleanup-forms, no special action is taken. The cleanup-forms of an `unwind-protect` are not protected by that `unwind-protect`, though they may be protected if that `unwind-protect` occurs within the protected form of another `unwind-protect`.) `unwind-protect` returns whatever results from evaluation of the protected-form and discards all the results from the cleanup-forms.

It should be emphasized that `unwind-protect` protects against all attempts to exit from the protected form, including not only ``dynamic exit'' facilities such as `throw` but also ``lexical exit'' facilities such as `go` and `return-from`. Consider this situation:

    (tagbody
      (let ((x 3))
        (unwind-protect
          (if (numberp x) (go out))
          (print x)))
     out
      ...)

When the `go` is executed, the call to `print` is executed first, and then the transfer of control to the tag `out` is completed.

X3J13 voted in March 1989 (EXIT-EXTENT) to clarify the interaction of `unwind-protect` with constructs that perform exits.

Let an exit be a point out of which control can be transferred. For a `throw` the exit is the matching `catch`; for a `return-from` the exit is the corresponding `block`. For a `go` the exit is the statement within the `tagbody` (the one to which the target tag belongs) which is being executed at the time the `go` is performed.

The extent of an exit is dynamic; it is not indefinite. The extent of an exit begins when the corresponding form (`catch`, `block`, or `tagbody` statement) is entered. When the extent of an exit has ended, it is no longer legal to return from it.

Note that the extent of an exit is not the same thing as the scope or extent of the designator by which the exit is identified. For example, a `block` name has lexical scope but the extent of its exit is dynamic. The extent of a `catch` tag could differ from the extent of the exit associated with the `catch` (which is exactly what is at issue here). The difference matters when there are transfers of control from the cleanup clauses of an `unwind-protect`.

When a transfer of control out of an exit is initiated by `throw`, `return-from`, or `go`, a variety of events occur before the transfer of control is complete:

- The cleanup clauses of any intervening `unwind-protect` clauses are evaluated.
- Intervening dynamic bindings of special variables and catch tags are undone.
- Intervening exits are abandoned, that is, their extent ends and it is no longer legal to attempt to transfer control from them.
- The extent of the exit being invoked ends.
- Control is finally passed to the target.

The first edition left the order of these events in some doubt. The implementation note for `throw` hinted that the first two processes are interwoven, but it was unclear whether it is permissible for an implementation to abandon all intervening exits before processing any intervening `unwind-protect` cleanup clauses.

The clarification adopted by X3J13 is as follows. Intervening exits are abandoned as soon as the transfer of control is initiated; in the case of a `throw`, this occurs at the beginning of the ``second pass'' mentioned in the implementation note. It is an error to attempt a transfer of control to an exit whose dynamic extent has ended.

Next the evaluation of `unwind-protect` cleanup clauses and the undoing of dynamic bindings and `catch` tags are performed together, in the order corresponding to the reverse of the order in which they were established. The effect of this is that the cleanup clauses of an `unwind-protect` will see the same dynamic bindings of variables and `catch` tags as were visible when the `unwind-protect` was entered. (However, some of those `catch` tags may not be useable because they correspond to abandoned exit points.)

Finally control is transferred to the originally invoked exit and simultaneously that exit is abandoned.

The effect of this specification is that once a program has attempted to transfer control to a particular exit, an `unwind-protect` cleanup form cannot step in and decide to transfer control to a more recent (nested) exit, blithely forgetting the original exit request. However, a cleanup form may restate the request to transfer to the same exit that started the cleanup process.

Here is an example based on a nautical metaphor. The function `gently` moves an oar in the water with low force, but if an oar gets stuck, the caller will catch a crab. The function `row` takes a boat, an oar-stroking function, a stream, and a count; an oar is constructed for the boat and stream and the oar-stroking function is called `:count` times. The function `life` rows a particular boat. Merriment follows, except that if the oarsman is winded he must stop to catch his breath.

    (defun gently (oar)
      (stroke oar :force 0.5)
      (when (stuck oar)
        (throw 'crab nil)))

    (defun row (boat stroke-fn stream &key count)
      (let ((oar (make-oar boat stream)))
        (loop repeat count do (funcall stroke-fn oar))))

    (defun life ()
      (catch 'crab
        (catch 'breath
          (unwind-protect
            (row *your-boat* #'gently *query-io* :count 3))
            (when (winded) (throw 'breath nil)))
          (loop repeat 4 (set-mode :merry))
          (dream))))

Suppose that the oar gets stuck, causing `gently` to call `throw` with the tag `crab`. The program is then committed to exiting from the outer `catch` (the one with the tag `crab`). As control breaks out of the `unwind-protect` form, the `winded` test is executed. Suppose it is true; then another call to `throw` occurs, this time with the tag `breath`. The inner `catch` (the one with the tag `breath`) has been abandoned as a result of the first `throw` operation (still in progress). The clarification voted by X3J13 specifies that the program is in error for attempting to transfer control to an abandoned exit point. To put it in terms of the example: once you have begun to catch a crab, you cannot rely on being able to catch your breath.

Implementations may support longer extents for exits than is required by this specification, but portable programs may not rely on such extended extents.

(This specification is somewhat controversial. An alternative proposal was that the abandoning of exits should be lumped in with the evaluation of `unwind-protect` cleanup clauses and the undoing of dynamic bindings and `catch` tags, performing all in reverse order of establishment. X3J13 agreed that this approach is theoretically cleaner and more elegant but also more stringent and of little additional practical use. There was some concern that a more stringent specification might be a great added burden to some implementors and would achieve only a small gain for users.)

[Special Form]
`throw` `tag` `result`

The `throw` special form transfers control to a matching `catch` construct. The tag is evaluated first to produce an object called the throw tag; then the result form is evaluated, and its results are saved (if the result form produces multiple values, then all the values are saved). The most recent outstanding catch whose tag matches the throw tag is exited; the saved results are returned as the value(s) of the catch. A `catch` matches only if the catch tag is `eq` to the throw tag.

In the process, dynamic variable bindings are undone back to the point of the catch, and any intervening `unwind-protect` cleanup code is executed. The result form is evaluated before the unwinding process commences, and whatever results it produces are returned from the catch.

If there is no outstanding catcher whose tag matches the throw tag, no unwinding of the stack is performed, and an error is signalled. When the error is signalled, the outstanding catchers and the dynamic variable bindings are those in force at the point of the throw.

Implementation note: These requirements imply that throwing should typically make two passes over the control stack. In the first pass it simply searches for a matching catch. In this search every `catch` must be considered, but every `unwind-protect` should be ignored. On the second pass the stack is actually unwound, one frame at a time, undoing dynamic bindings and outstanding `unwind-protect` constructs in reverse order of creation until the matching catch is reached.

Compatibility note: The name `throw` comes from MacLisp, but the syntax of `throw` in Common Lisp is different. The MacLisp syntax was `(throw form tag)`, where the tag was not evaluated.

Next: Macros Up: Control Structure Previous: Rules Governing the