Explicit Nonlocal Exits: `catch' and `throw'
--------------------------------------------
Most control constructs affect only the flow of control within the
construct itself. The function `throw' is the exception to this rule
of normal program execution: it performs a nonlocal exit on request.
(There are other exceptions, but they are for error handling only.)
`throw' is used inside a `catch', and jumps back to that `catch'. For
example:
(defun foo-outer ()
(catch 'foo
(foo-inner)))
(defun foo-inner ()
...
(if x
(throw 'foo t))
...)
The `throw' form, if executed, transfers control straight back to the
corresponding `catch', which returns immediately. The code following
the `throw' is not executed. The second argument of `throw' is used as
the return value of the `catch'.
The function `throw' finds the matching `catch' based on the first
argument: it searches for a `catch' whose first argument is `eq' to the
one specified in the `throw'. If there is more than one applicable
`catch', the innermost one takes precedence. Thus, in the above
example, the `throw' specifies `foo', and the `catch' in `foo-outer'
specifies the same symbol, so that `catch' is the applicable one
(assuming there is no other matching `catch' in between).
Executing `throw' exits all Lisp constructs up to the matching
`catch', including function calls. When binding constructs such as
`let' or function calls are exited in this way, the bindings are
unbound, just as they are when these constructs exit normally (Note:Local Variables). Likewise, `throw' restores the buffer and position
saved by `save-excursion' (Note:Excursions), and the narrowing
status saved by `save-restriction' and the window selection saved by
`save-window-excursion' (Note:Window Configurations). It also runs
any cleanups established with the `unwind-protect' special form when it
exits that form (Note:Cleanups).
The `throw' need not appear lexically within the `catch' that it
jumps to. It can equally well be called from another function called
within the `catch'. As long as the `throw' takes place chronologically
after entry to the `catch', and chronologically before exit from it, it
has access to that `catch'. This is why `throw' can be used in
commands such as `exit-recursive-edit' that throw back to the editor
command loop (Note:Recursive Editing).
Common Lisp note: Most other versions of Lisp, including Common
Lisp, have several ways of transferring control nonsequentially:
`return', `return-from', and `go', for example. Emacs Lisp has
only `throw'.
- Special Form: catch tag body...
`catch' establishes a return point for the `throw' function. The
return point is distinguished from other such return points by
TAG, which may be any Lisp object except `nil'. The argument TAG
is evaluated normally before the return point is established.
With the return point in effect, `catch' evaluates the forms of the
BODY in textual order. If the forms execute normally (without
error or nonlocal exit) the value of the last body form is
returned from the `catch'.
If a `throw' is executed during the execution of BODY, specifying
the same value TAG, the `catch' form exits immediately; the value
it returns is whatever was specified as the second argument of
`throw'.
- Function: throw tag value
The purpose of `throw' is to return from a return point previously
established with `catch'. The argument TAG is used to choose
among the various existing return points; it must be `eq' to the
value specified in the `catch'. If multiple return points match
TAG, the innermost one is used.
The argument VALUE is used as the value to return from that
`catch'.
If no return point is in effect with tag TAG, then a `no-catch'
error is signaled with data `(TAG VALUE)'.