6.11.8.2 Raising and Handling Exceptions

An exception object describes an exceptional situation. To bring that description to the attention of the user or to handle the situation programmatically, the first step is to raise the exception.

Scheme Procedure: raise-exception obj [#:continuable?=#f]

Raise an exception by invoking the current exception handler on obj. The handler is called with a continuation whose dynamic environment is that of the call to raise, except that the current exception handler is the one that was in place when the handler being called was installed.

If continuable? is true, the handler is invoked in tail position relative to the raise-exception call. Otherwise if the handler returns, a non-continuable exception of type &non-continuable is raised in the same dynamic environment as the handler.

As the above description notes, Guile has a notion of a current exception handler. At the REPL, this exception handler may enter a recursive debugger; in a standalone program, it may simply print a representation of the error and exit.

To establish an exception handler within the dynamic extent of a call, use with-exception-handler.

Scheme Procedure: with-exception-handler handler thunk [#:unwind?=#f] [#:unwind-for-type=#t]

Establish handler, a procedure of one argument, as the current exception handler during the dynamic extent of invoking thunk.

If raise-exception is called during the dynamic extent of invoking thunk, handler will be invoked on the argument of raise-exception.

There are two kinds of exception handlers: unwinding and non-unwinding.

By default, exception handlers are non-unwinding. Unless with-exception-handler was invoked with #:unwind? #t, exception handlers are invoked within the continuation of the error, without unwinding the stack. The dynamic environment of the handler call will be that of the raise-exception call, with the difference that the current exception handler will be “unwound” to the “outer” handler (the one that was in place when the corresponding with-exception-handler was called).

However, it’s often the case that one would like to handle an exception by unwinding the computation to an earlier state and running the error handler there. After all, unless the raise-exception call is continuable, the exception handler needs to abort the continuation. To support this use case, if with-exception-handler was invoked with #:unwind? #t is true, raise-exception will first unwind the stack by invoking an escape continuation (see call/ec), and then invoke the handler with the continuation of the with-exception-handler call.

Finally, one more wrinkle: for unwinding exception handlers, it can be useful to Guile if it can determine whether an exception handler would indeed handle a particular exception or not. This is especially the case for exceptions raised in resource-exhaustion scenarios like stack-overflow or out-of-memory, where you want to immediately shrink resource use before recovering. See Stack Overflow. For this purpose, the #:unwind-for-type keyword argument allows users to specify the kind of exception handled by an exception handler; if #t, all exceptions will be handled; if an exception type object, only exceptions of that type will be handled; otherwise if a symbol, only that exceptions with the given exception-kind will be handled.