Skip to main content

throw

throw Special Operator

Syntax:

throw tag result-form →

Arguments and Values:

tag—a catch tag; evaluated.

result-form—a form; evaluated as described below.

Data and Control

throw

Description:

throw causes a non-local control transfer to a catch whose tag is eq to tag.

Tag is evaluated first to produce an object called the throw tag; then 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 is eq to the throw tag is exited; the saved results are returned as the value or values of catch.

The transfer of control initiated by throw is performed as described in Section 5.2 (Transfer of Control to an Exit Point).

Examples:

(catch ’result 
(setq i 0 j 0)
(loop (incf j 3) (incf i)
(if (= i 3) (throw ’result (values i j))))) → 3, 9
(catch nil
(unwind-protect (throw nil 1)
(throw nil 2)))2
The consequences of the following are undefined because the **catch** of b is passed over by the first **throw**, hence portable programs must assume that its *dynamic extent* is terminated. The *binding* of the *catch tag* is not yet *disestablished* and therefore it is the target of the second **throw**.
(catch ’a
(catch ’b
(unwind-protect (throw ’a 1)
(throw ’b 2))))
The following prints “The inner catch returns :SECOND-THROW” and then returns :outer-catch.
(catch ’foo
(format t "The inner catch returns ~s.~%"
(catch ’foo
(unwind-protect (throw ’foo :first-throw)
(throw ’foo :second-throw))))
:outer-catch)
▷ The inner catch returns :SECOND-THROW
:OUTER-CATCH

Exceptional Situations:

If there is no outstanding catch tag that matches the throw tag, no unwinding of the stack is

performed, and an error of type control-error is signaled. When the error is signaled, the dynamic environment is that which was in force at the point of the throw.

See Also:

block, catch, return-from, unwind-protect, Section 3.1 (Evaluation)

Notes:

catch and throw are normally used when the exit point must have dynamic scope (e.g., the throw is not lexically enclosed by the catch), while block and return are used when lexical scope is sufficient.

Expanded Reference: throw

Basic throw to a catch tag

throw causes a non-local transfer of control to the dynamically most recent catch whose tag is eq to the throw tag. The result form is evaluated and its values are returned from the catch.

(catch 'done
(throw 'done 99))
=> 99

throw across function boundaries

throw works dynamically, not lexically, so it can exit from deeply nested function calls.

(defun inner ()
(throw 'abort :bailed-out))

(defun middle ()
(inner)
(print "not reached"))

(catch 'abort
(middle))
=> :BAILED-OUT

Throwing multiple values

The result form of throw can produce multiple values, which are all passed to catch.

(catch 'result
(let ((i 0) (j 0))
(loop
(incf j 3)
(incf i)
(when (= i 3)
(throw 'result (values i j))))))
=> 3
=> 9

Error when no matching catch exists

If there is no outstanding catch with a matching tag, a control-error is signaled.

;; This would signal an error:
;; (throw 'nonexistent-tag 42)
;; => ERROR: There is no outstanding catch for the tag NONEXISTENT-TAG

throw evaluates the tag

The tag argument to throw is evaluated, so it can be a variable or expression.

(defun throw-to (tag value)
(throw tag value))

(catch 'exit
(throw-to 'exit :done))
=> :DONE

Interaction with unwind-protect

When throw transfers control, any intervening unwind-protect cleanup forms are executed during the unwinding.

(catch 'outer
(unwind-protect
(throw 'outer :result)
(format t "cleanup~%")))
.. cleanup
..
=> :RESULT