1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Update documentation for with-exception-handler et al

* doc/ref/api-control.texi (Prompt Primitives): Reference the newer
  exception facilities.
  (Exceptions): Rewrite to use the new exception primitives.
  (Exception Terminology): Remove superfluous section.
  (Exception Objects): New section.
  (Raising and Handling Exceptions): New section.
  (Throw and Catch): New section, coalescing the previous catch,
  with-throw-handler, and throw sections.
  (Exceptions and C): New section, for miscellaneous procedures.
  (Handling Errors): Mention the transitional period regarding exception
  handling.
* doc/ref/api-debug.texi (Catching Exceptions): Rewrite to use newer
  exception facilities.
  (Capturing Stacks): Remove, as it's not really recommendable any
  more.
  (Pre-Unwind Debugging): Rewrite to use the new primitives.
  (Standard Error Handling): Add note about transitional status.
  (Stack Overflow): Reference new exception section.
* doc/ref/api-scheduling.texi (Mutexes and Condition Variables):
  Reference new exception section.
* doc/ref/r6rs.texi (rnrs exceptions, rnrs conditions): Update to
  mention compatibility with SRFI-34/35 and to relate to core
  exceptions.
* doc/ref/srfi-modules.texi (SRFI-34): Document.
This commit is contained in:
Andy Wingo 2019-11-13 22:26:31 +01:00
parent f4ca107f7f
commit 44ee8c5559
5 changed files with 638 additions and 603 deletions

View file

@ -18,7 +18,7 @@ flow of Scheme affects C code.
* Prompts:: Composable, delimited continuations.
* Continuations:: Non-composable continuations.
* Multiple Values:: Returning and accepting multiple values.
* Exceptions:: Throwing and catching exceptions.
* Exceptions:: Raising and handling exceptions.
* Error Reporting:: Procedures for signaling errors.
* Dynamic Wind:: Dealing with non-local entrance/exit.
* Fluids and Dynamic States:: Dynamic scope building blocks.
@ -514,12 +514,13 @@ Unwind the dynamic and control context to the nearest prompt named @var{tag},
also passing the given values.
@end deffn
C programmers may recognize @code{call-with-prompt} and @code{abort-to-prompt}
as a fancy kind of @code{setjmp} and @code{longjmp}, respectively. Prompts are
indeed quite useful as non-local escape mechanisms. Guile's @code{catch} and
@code{throw} are implemented in terms of prompts. Prompts are more convenient
than @code{longjmp}, in that one has the opportunity to pass multiple values to
the jump target.
C programmers may recognize @code{call-with-prompt} and
@code{abort-to-prompt} as a fancy kind of @code{setjmp} and
@code{longjmp}, respectively. Prompts are indeed quite useful as
non-local escape mechanisms. Guile's @code{with-exception-handler} and
@code{raise-exception} are implemented in terms of prompts. Prompts are
more convenient than @code{longjmp}, in that one has the opportunity to
pass multiple values to the jump target.
Also unlike @code{longjmp}, the prompt handler is given the full state of the
process that was aborted, as the first argument to the prompt's handler. That
@ -586,7 +587,7 @@ important efficiency consideration to keep in mind.
One example where this optimization matters is @dfn{escape
continuations}. Escape continuations are delimited continuations whose
only use is to make a non-local exit---i.e., to escape from the current
continuation. A common use of escape continuations is when throwing an
continuation. A common use of escape continuations is when handling an
exception (@pxref{Exceptions}).
The constructs below are syntactic sugar atop prompts to simplify the
@ -996,12 +997,20 @@ For example getting results from @code{partition} in SRFI-1
@cindex error handling
@cindex exception handling
A common requirement in applications is to want to jump
@dfn{non-locally} from the depths of a computation back to, say, the
application's main processing loop. Usually, the place that is the
target of the jump is somewhere in the calling stack of procedures that
called the procedure that wants to jump back. For example, typical
logic for a key press driven application might look something like this:
What happens when things go wrong? Guile's exception facility exists to
help answer this question, allowing programs to describe the problem and
to handle the situation in a flexible way.
When a program runs into a problem, such as division by zero, it will
raise an exception. Sometimes exceptions get raised by Guile on a
program's behalf. Sometimes a program will want to raise exceptions of
its own. Raising an exception stops the current computation and instead
invokes the current exception handler, passing it an exception object
describing the unexpected situation.
Usually an exception handler will unwind the computation back to some
kind of safe point. For example, typical logic for a key press driven
application might look something like this:
@example
main-loop:
@ -1016,175 +1025,493 @@ find-file:
find-specified-file
find-specified-file:
check whether file exists; if not, jump back to main-loop
check whether file exists; if not, raise an exception
@dots{}
@end example
The jump back to @code{main-loop} could be achieved by returning through
the stack one procedure at a time, using the return value of each
procedure to indicate the error condition, but Guile (like most modern
programming languages) provides an additional mechanism called
@dfn{exception handling} that can be used to implement such jumps much
more conveniently.
In this case, @code{main-loop} can install an exception handler that
would cause any exception raised inside @code{dispatch-key} to print a
warning and jump back to the main loop.
The following subsections go into more detail about exception objects,
raising exceptions, and handling exceptions. It also presents a
historical interface that was used in Guile's first 25 years and which
won't be going away any time soon.
@menu
* Exception Terminology:: Different ways to say the same thing.
* Catch:: Setting up to catch exceptions.
* Throw Handlers:: Handling exceptions before unwinding the stack.
* Throw:: Throwing an exception.
* Exception Implementation:: How Guile implements exceptions.
* Exception Objects:: What went wrong?
* Raising and Handling Exceptions:: What to do when something goes wrong.
* Throw and Catch:: An older approach to exceptions.
* Exceptions and C:: Specialized interfaces for C.
@end menu
@node Exception Terminology
@subsubsection Exception Terminology
@node Exception Objects
@subsubsection Exception Objects
There are several variations on the terminology for dealing with
non-local jumps. It is useful to be aware of them, and to realize
that they all refer to the same basic mechanism.
When Guile encounters an exceptional situation, it raises an exception,
where the exception is an object that describes the exceptional
situation. Exception objects are structured data, built on the record
facility (@pxref{Records}).
@itemize @bullet
@item
Actually making a non-local jump may be called @dfn{raising an
exception}, @dfn{raising a signal}, @dfn{throwing an exception} or
@dfn{doing a long jump}. When the jump indicates an error condition,
people may talk about @dfn{signalling}, @dfn{raising} or @dfn{throwing}
@dfn{an error}.
@deftp {Exception Type} &exception
The base exception type. All exception objects are composed of
instances of subtypes of @code{&exception}.
@end deftp
@item
Handling the jump at its target may be referred to as @dfn{catching} or
@dfn{handling} the @dfn{exception}, @dfn{signal} or, where an error
condition is involved, @dfn{error}.
@end itemize
@deffn {Scheme Procedure} exception-type? obj
Return true if @var{obj} is an exception type.
@end deffn
Where @dfn{signal} and @dfn{signalling} are used, special care is needed
to avoid the risk of confusion with POSIX signals.
Exception types exist in a hierarchy. New exception types can be
defined using @code{make-exception-type}.
This manual prefers to speak of throwing and catching exceptions, since
this terminology matches the corresponding Guile primitives.
@deffn {Scheme Procedure} make-exception-type id parent field-names
Return a new exception type named @var{id}, inheriting from
@var{parent}, and with the fields whose names are listed in
@var{field-names}. @var{field-names} must be a list of symbols and must
not contain names already used by @var{parent} or one of its supertypes.
@end deffn
The exception mechanism described in this section has connections with
@dfn{delimited continuations} (@pxref{Prompts}). In particular,
throwing an exception is akin to invoking an @dfn{escape continuation}
(@pxref{Prompt Primitives, @code{call/ec}}).
Exception type objects are record type objects, and as such, one can use
@code{record-constructor} on an exception type to get its constructor.
The constructor will take as many arguments as the exception has fields
(including supertypes). @xref{Records}.
However, @code{record-predicate} and @code{record-accessor} aren't
usually what you want to use as exception type predicates and field
accessors. The reason is, instances of exception types can be composed
into @dfn{compound exceptions}. Exception accessors should pick out the
specific component of a compound exception, and then access the field on
that specific component.
@deffn {Scheme Procedure} make-exception exceptions @dots{}
Return an exception object composed of @var{exceptions}.
@end deffn
@deffn {Scheme Procedure} exception? obj
Return true if @var{obj} is an exception object.
@end deffn
@deffn {Scheme Procedure} exception-predicate type
Return a procedure that will return true if its argument is a simple
exception that is an instance of @var{type}, or a compound exception
composed of such an instance.
@end deffn
@deffn {Scheme Procedure} exception-accessor rtd proc
Return a procedure that will tail-call @var{proc} on an instance of the
exception type @var{rtd}, or on the component of a compound exception
that is an instance of @var{rtd}.
@end deffn
Compound exceptions are useful to separately express the different
aspects of a situation. For example, compound exceptions allow a
programmer to say that ``this situation is a programming error, and also
here's a useful message to show to the user, and here are some relevant
objects that can give more information about the error''. This error
could be composed of instances of the @code{&programming-error},
@code{&message}, and @code{&irritants} exception types.
The subtyping relationship in exceptions is useful to let
different-but-similar situations to be treated the same; for example
there are many varieties of programming errors (for example,
divide-by-zero or type mismatches), but perhaps there are common ways
that the user would like to handle them all, and that common way might
be different than how one might handle an error originating outside the
program (for example, a file-not-found error).
The standard exception hierarchy in Guile takes its cues from R6RS,
though the names of some of the types are different. @xref{rnrs
exceptions}, for more details.
To have access to Guile's exception type hierarchy, import the
@code{(ice-9 exceptions)} module:
@example
(use-modules (ice-9 exceptions))
@end example
The following diagram gives an overview of the standard exception type
hierarchy.
@example
&exception
|- &warning
|- &message
|- &irritants
|- &origin
\- &error
|- &external-error
\- &programming-error
|- &assertion-failure
|- &non-continuable
|- &implementation-restriction
|- &lexical
|- &syntax
\- &undefined-variable
@end example
@deftp {Exception Type} &warning
An exception type denoting warnings. These are usually raised using
@code{#:continuable? #t}; see the @code{raise-exception} documentation
for more.
@end deftp
@deffn {Scheme Procedure} make-warning
@deffnx {Scheme Procedure} warning? obj
Constructor and predicate for @code{&warning} exception objects.
@end deffn
@deftp {Exception Type} &message message
An exception type that provides a message to display to the user.
Usually used as a component of a compound exception.
@end deftp
@deffn {Scheme Procedure} make-exception-with-message message
@deffnx {Scheme Procedure} exception-with-message? obj
@deffnx {Scheme Procedure} exception-message exn
Constructor, predicate, and accessor for @code{&message} exception
objects.
@end deffn
@deftp {Exception Type} &irritants irritants
An exception type that provides a list of objects that were unexpected
in some way. Usually used as a component of a compound exception.
@end deftp
@deffn {Scheme Procedure} make-exception-with-irritants irritants
@deffnx {Scheme Procedure} exception-with-irritants? obj
@deffnx {Scheme Procedure} exception-irritants exn
Constructor, predicate, and accessor for @code{&irritants} exception
objects.
@end deffn
@deftp {Exception Type} &origin origin
An exception type that indicates the origin of an exception, typically
expressed as a procedure name, as a symbol. Usually used as a component
of a compound exception.
@end deftp
@deffn {Scheme Procedure} make-exception-with-origin origin
@deffnx {Scheme Procedure} exception-with-origin? obj
@deffnx {Scheme Procedure} exception-origin exn
Constructor, predicate, and accessor for @code{&origin} exception
objects.
@end deffn
@deftp {Exception Type} &error
An exception type denoting errors: situations that are not just
exceptional, but wrong.
@end deftp
@deffn {Scheme Procedure} make-error
@deffnx {Scheme Procedure} error? obj
Constructor and predicate for @code{&error} exception objects.
@end deffn
@deftp {Exception Type} &external-error
An exception type denoting errors that proceed from the interaction of
the program with the world, for example a ``file not found'' error.
@end deftp
@deffn {Scheme Procedure} make-external-error
@deffnx {Scheme Procedure} external-error? obj
Constructor and predicate for @code{&external-error} exception objects.
@end deffn
@deftp {Exception Type} &programming-error
An exception type denoting errors that proceed from inside a program:
type mismatches and so on.
@end deftp
@deffn {Scheme Procedure} make-programming-error
@deffnx {Scheme Procedure} programming-error? obj
Constructor and predicate for @code{&programming-error} exception
objects.
@end deffn
@deftp {Exception Type} &non-continuable
An exception type denoting errors that proceed from inside a program:
type mismatches and so on.
@end deftp
@deffn {Scheme Procedure} make-non-continuable-error
@deffnx {Scheme Procedure} non-continuable-error? obj
Constructor and predicate for @code{&non-continuable} exception objects.
@end deffn
@deftp {Exception Type} &lexical
An exception type denoting lexical errors, for example unbalanced
parentheses.
@end deftp
@deffn {Scheme Procedure} make-lexical-error
@deffnx {Scheme Procedure} lexical-error? obj
Constructor and predicate for @code{&lexical} exception objects.
@end deffn
@deftp {Exception Type} &syntax form subform
An exception type denoting syntax errors, for example a @code{cond}
expression with invalid syntax. The @var{form} field indicates the form
containing the error, and @var{subform} indicates the unexpected
subcomponent, or @code{#f} if unavailable.
@end deftp
@deffn {Scheme Procedure} make-syntax-error form subform
@deffnx {Scheme Procedure} syntax-error? obj
@deffnx {Scheme Procedure} syntax-error-form exn
@deffnx {Scheme Procedure} syntax-error-subform exn
Constructor, predicate, and accessors for @code{&syntax} exception
objects.
@end deffn
@deftp {Exception Type} &undefined-variable
An exception type denoting undefined variables.
@end deftp
@deffn {Scheme Procedure} make-undefine-variable-error
@deffnx {Scheme Procedure} undefined-variable-error? obj
Constructor and predicate for @code{&undefined-variable} exception
objects.
@end deffn
Incidentally, the @code{(ice-9 exceptions)} module also includes a
@code{define-exception-type} macro that can be used to conveniently add
new exception types to the hierarchy.
@deffn {Syntax} define-exception-type name parent @
constructor predicate @
(field accessor) @dots{}
Define @var{name} to be a new exception type, inheriting from
@var{parent}. Define @var{constructor} and @var{predicate} to be the
exception constructor and predicate, respectively, and define an
@var{accessor} for each @var{field}.
@end deffn
@node Catch
@subsubsection Catching Exceptions
@node Raising and Handling Exceptions
@subsubsection Raising and Handling Exceptions
@code{catch} is used to set up a target for a possible non-local jump.
The arguments of a @code{catch} expression are a @dfn{key}, which
restricts the set of exceptions to which this @code{catch} applies, a
thunk that specifies the code to execute and one or two @dfn{handler}
procedures that say what to do if an exception is thrown while executing
the code. If the execution thunk executes @dfn{normally}, which means
without throwing any exceptions, the handler procedures are not called
at all.
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 @dfn{raise} the exception.
When an exception is thrown using the @code{throw} function, the first
argument of the @code{throw} is a symbol that indicates the type of the
exception. For example, Guile throws an exception using the symbol
@code{numerical-overflow} to indicate numerical overflow errors such as
division by zero:
@deffn {Scheme Procedure} raise-exception obj [#:continuable=#f]
Raise an exception by invoking the current exception handler on
@var{obj}. The handler is called with a continuation whose dynamic
environment is that of the call to @code{raise}, except that the current
exception handler is the one that was in place when the handler being
called was installed.
@lisp
(/ 1 0)
@result{}
ABORT: (numerical-overflow)
@end lisp
If @var{continuable?} is true, the handler is invoked in tail position
relative to the @code{raise-exception} call. Otherwise if the handler
returns, a non-continuable exception of type @code{&non-continuable} is
raised in the same dynamic environment as the handler.
@end deffn
The @var{key} argument in a @code{catch} expression corresponds to this
symbol. @var{key} may be a specific symbol, such as
@code{numerical-overflow}, in which case the @code{catch} applies
specifically to exceptions of that type; or it may be @code{#t}, which
means that the @code{catch} applies to all exceptions, irrespective of
their type.
As the above description notes, Guile has a notion of a @dfn{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.
The second argument of a @code{catch} expression should be a thunk
(i.e.@: a procedure that accepts no arguments) that specifies the normal
case code. The @code{catch} is active for the execution of this thunk,
including any code called directly or indirectly by the thunk's body.
Evaluation of the @code{catch} expression activates the catch and then
calls this thunk.
To establish an exception handler within the dynamic extent of a call,
use @code{with-exception-handler}.
The third argument of a @code{catch} expression is a handler procedure.
If an exception is thrown, this procedure is called with exactly the
arguments specified by the @code{throw}. Therefore, the handler
procedure must be designed to accept a number of arguments that
corresponds to the number of arguments in all @code{throw} expressions
that can be caught by this @code{catch}.
@deffn {Scheme Procedure} with-exception-handler handler thunk @
[#:unwind?=#f] [#:unwind-for-type=#t]
Establish @var{handler}, a procedure of one argument, as the current
exception handler during the dynamic extent of invoking @var{thunk}.
The fourth, optional argument of a @code{catch} expression is another
handler procedure, called the @dfn{pre-unwind} handler. It differs from
the third argument in that if an exception is thrown, it is called,
@emph{before} the third argument handler, in exactly the dynamic context
of the @code{throw} expression that threw the exception. This means
that it is useful for capturing or displaying the stack at the point of
the @code{throw}, or for examining other aspects of the dynamic context,
such as fluid values, before the context is unwound back to that of the
prevailing @code{catch}.
If @code{raise-exception} is called during the dynamic extent of
invoking @var{thunk}, @var{handler} will be invoked on the argument of
@code{raise-exception}.
@end deffn
There are two kinds of exception handlers: unwinding and non-unwinding.
By default, exception handlers are non-unwinding. Unless
@code{with-exception-handler} was invoked with @code{#: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 @code{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
@code{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 @code{raise-exception} call is
continuable, the exception handler needs to abort the continuation. To
support this use case, if @code{with-exception-handler} was invoked with
@code{#:unwind? #t} is true, @code{raise-exception} will first unwind
the stack by invoking an @dfn{escape continuation} (@pxref{Prompt
Primitives, @code{call/ec}}), and then invoke the handler with the
continuation of the @code{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
@code{stack-overflow} or @code{out-of-memory}, where you want to
immediately shrink resource use before recovering. @xref{Stack
Overflow}. For this purpose, the @code{#:unwind-for-type} keyword
argument allows users to specify the kind of exception handled by an
exception handler; if @code{#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
@code{exception-kind} will be handled.
@node Throw and Catch
@subsubsection Throw and Catch
Guile only adopted @code{with-exception-handler} and
@code{raise-exception} as its primary exception-handling facility in
2019. Before then, exception handling was fundamentally based on three
other primitives with a somewhat more complex interface: @code{catch},
@code{with-throw-handler}, and @code{throw}.
@deffn {Scheme Procedure} catch key thunk handler [pre-unwind-handler]
@deffnx {C Function} scm_catch_with_pre_unwind_handler (key, thunk, handler, pre_unwind_handler)
@deffnx {C Function} scm_catch (key, thunk, handler)
Invoke @var{thunk} in the dynamic context of @var{handler} for
exceptions matching @var{key}. If thunk throws to the symbol
@var{key}, then @var{handler} is invoked this way:
@lisp
(handler key args ...)
@end lisp
Establish an exception handler during the dynamic extent of the call to
@var{thunk}. @var{key} is either @code{#t}, indicating that all
exceptions should be handled, or a symbol, restricting the exceptions
handled to those having the @var{key} as their @code{exception-kind}.
@var{key} is a symbol or @code{#t}.
@var{thunk} takes no arguments. If @var{thunk} returns
normally, that is the return value of @code{catch}.
Handler is invoked outside the scope of its own @code{catch}.
If @var{handler} again throws to the same key, a new handler
from further up the call chain is invoked.
If the key is @code{#t}, then a throw to @emph{any} symbol will
match this call to @code{catch}.
If a @var{pre-unwind-handler} is given and @var{thunk} throws
an exception that matches @var{key}, Guile calls the
@var{pre-unwind-handler} before unwinding the dynamic state and
invoking the main @var{handler}. @var{pre-unwind-handler} should
be a procedure with the same signature as @var{handler}, that
is @code{(lambda (key . args))}. It is typically used to save
the stack at the point where the exception occurred, but can also
query other parts of the dynamic state at that point, such as
fluid values.
A @var{pre-unwind-handler} can exit either normally or non-locally.
If it exits normally, Guile unwinds the stack and dynamic context
and then calls the normal (third argument) handler. If it exits
non-locally, that exit determines the continuation.
If @var{thunk} executes normally, meaning without throwing any
exceptions, the handler procedures are not called at all and the result
of the @code{thunk} call is the result of the @code{catch}. Otherwise
if an exception is thrown that matches @var{key}, @var{handler} is
called with the continuation of the @code{catch} call.
@end deffn
If a handler procedure needs to match a variety of @code{throw}
expressions with varying numbers of arguments, you should write it like
this:
Given the discussion from the previous section, it is most precise and
concise to specify what @code{catch} does by expressing it in terms of
@code{with-exception-handler}. Calling @code{catch} with the three
arguments is the same as:
@example
(define (catch key thunk handler)
(with-exception-handler
(lambda (exn)
(apply handler (exception-kind exn) (exception-args exn)))
thunk
#:unwind? #t
#:unwind-for-type key))
@end example
By invoking @code{with-exception-handler} with @code{#:unwind? #t},
@code{catch} sets up an escape continuation that will be invoked in an
exceptional situation before the handler is called.
If @code{catch} is called with four arguments, then the use of
@var{thunk} should be replaced with:
@example
(lambda ()
(with-throw-handler key thunk pre-unwind-handler))
@end example
As can be seen above, if a pre-unwind-handler is passed to @code{catch},
it's like calling @code{with-throw-handler} inside the body thunk.
@code{with-throw-handler} is the second of the older primitives, and is
used to be able to intercept an exception that is being thrown before
the stack is unwound. This could be to clean up some related state, to
print a backtrace, or to pass information about the exception to a
debugger, for example.
@deffn {Scheme Procedure} with-throw-handler key thunk handler
@deffnx {C Function} scm_with_throw_handler (key, thunk, handler)
Add @var{handler} to the dynamic context as a throw handler
for key @var{key}, then invoke @var{thunk}.
@end deffn
It's not possible to exactly express @code{with-throw-handler} in terms
of @code{with-exception-handler}, but we can get close.
@example
(define (with-throw-handler key thunk handler)
(with-exception-handler
(lambda (exn)
(when (or (eq? key #t) (eq? key (exception-kind exn)))
(apply handler (exception-kind exn) (exception-args exn)))
(raise-exception exn))
thunk))
@end example
As you can see, unlike in the case of @code{catch}, the handler for
@code{with-throw-handler} is invoked within the continuation of
@code{raise-exception}, before unwinding the stack. If the throw
handler returns normally, the exception will be re-raised, to be handled
by the next exception handler.
The special wrinkle of @code{with-throw-handler} that can't be shown
above is that if invoking the handler causes a @code{raise-exception}
instead of completing normally, the exception is thrown in the
@emph{original} dynamic environment of the @code{raise-exception}. Any
inner exception handler will get another shot at handling the exception.
Here is an example to illustrate this behavior:
@lisp
(lambda (key . args)
@dots{})
(catch 'a
(lambda ()
(with-throw-handler 'b
(lambda ()
(catch 'a
(lambda ()
(throw 'b))
inner-handler))
(lambda (key . args)
(throw 'a))))
outer-handler)
@end lisp
@noindent
The @var{key} argument is guaranteed always to be present, because a
@code{throw} without a @var{key} is not valid. The number and
interpretation of the @var{args} varies from one type of exception to
another, but should be specified by the documentation for each exception
type.
This code will call @code{inner-handler} and then continue with the
continuation of the inner @code{catch}.
Note that, once the normal (post-unwind) handler procedure is invoked,
the catch that led to the handler procedure being called is no longer
active. Therefore, if the handler procedure itself throws an exception,
that exception can only be caught by another active catch higher up the
call stack, if there is one.
Finally, we get to @code{throw}, which is the older equivalent to
@code{raise-exception}.
@deffn {Scheme Procedure} throw key arg @dots{}
@deffnx {C Function} scm_throw (key, args)
Raise an exception with kind @var{key} and arguments @var{args}.
@var{key} is a symbol, denoting the ``kind'' of the exception.
@end deffn
Again, we can specify what @code{throw} does by expressing it in terms
of @code{raise-exception}.
@example
(define (throw key . args)
(raise-exception (make-exception-from-throw key args)))
@end example
At this point, we should mention the primitive that manage the
relationship between structured exception objects @code{throw}.
@deffn {Scheme Procedure} make-exception-from-throw key args
Create an exception object for the given @var{key} and @var{args} passed
to @code{throw}. This may be a specific type of exception, for example
@code{&programming-error}; Guile maintains a set of custom transformers
for the various @var{key} values that have been used historically.
@end deffn
@deffn {Scheme Procedure} exception-kind exn
If @var{exn} is an exception created via
@code{make-exception-from-throw}, return the corresponding @var{key} for
the exception. Otherwise, unless @var{exn} is an exception of a type
with a known mapping to @code{throw}, return the symbol
@code{%exception}.
@end deffn
@deffn {Scheme Procedure} exception-args exn
If @var{exn} is an exception created via
@code{make-exception-from-throw}, return the corresponding @var{args}
for the exception. Otherwise, unless @var{exn} is an exception of a
type with a known mapping to @code{throw}, return @code{(list @var{exn})}.
@end deffn
@node Exceptions and C
@subsubsection Exceptions and C
There are some specific versions of Guile's original @code{catch} and
@code{with-throw-handler} exception-handling primitives that are still
widely used in C code.
@sp 1
@deftypefn {C Function} SCM scm_c_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data, scm_t_catch_handler pre_unwind_handler, void *pre_unwind_handler_data)
@deftypefnx {C Function} SCM scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
The above @code{scm_catch_with_pre_unwind_handler} and @code{scm_catch}
@ -1223,207 +1550,14 @@ value must be held on the stack. Another way is to use
Management}).
@end deftypefn
@node Throw Handlers
@subsubsection Throw Handlers
It's sometimes useful to be able to intercept an exception that is being
thrown before the stack is unwound. This could be to clean up some
related state, to print a backtrace, or to pass information about the
exception to a debugger, for example. The @code{with-throw-handler}
procedure provides a way to do this.
@deffn {Scheme Procedure} with-throw-handler key thunk handler
@deffnx {C Function} scm_with_throw_handler (key, thunk, handler)
Add @var{handler} to the dynamic context as a throw handler
for key @var{key}, then invoke @var{thunk}.
This behaves exactly like @code{catch}, except that it does not unwind
the stack before invoking @var{handler}. If the @var{handler} procedure
returns normally, Guile rethrows the same exception again to the next
innermost catch or throw handler. @var{handler} may exit nonlocally, of
course, via an explicit throw or via invoking a continuation.
@end deffn
Typically @var{handler} is used to display a backtrace of the stack at
the point where the corresponding @code{throw} occurred, or to save off
this information for possible display later.
Not unwinding the stack means that throwing an exception that is handled
via a throw handler is equivalent to calling the throw handler handler
inline instead of each @code{throw}, and then omitting the surrounding
@code{with-throw-handler}. In other words,
@lisp
(with-throw-handler 'key
(lambda () @dots{} (throw 'key args @dots{}) @dots{})
handler)
@end lisp
@noindent
is mostly equivalent to
@lisp
((lambda () @dots{} (handler 'key args @dots{}) @dots{}))
@end lisp
In particular, the dynamic context when @var{handler} is invoked is that
of the site where @code{throw} is called. The examples are not quite
equivalent, because the body of a @code{with-throw-handler} is not in
tail position with respect to the @code{with-throw-handler}, and if
@var{handler} exits normally, Guile arranges to rethrow the error, but
hopefully the intention is clear. (For an introduction to what is meant
by dynamic context, @xref{Dynamic Wind}.)
@deftypefn {C Function} SCM scm_c_with_throw_handler (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data, int lazy_catch_p)
The above @code{scm_with_throw_handler} takes Scheme procedures as body
(thunk) and handler arguments. @code{scm_c_with_throw_handler} is an
equivalent taking C functions. See @code{scm_c_catch} (@pxref{Catch})
for a description of the parameters, the behaviour however of course
follows @code{with-throw-handler}.
equivalent taking C functions. See @code{scm_c_catch}
(@pxref{Exceptions and C}) for a description of the parameters, the
behaviour however of course follows @code{with-throw-handler}.
@end deftypefn
If @var{thunk} throws an exception, Guile handles that exception by
invoking the innermost @code{catch} or throw handler whose key matches
that of the exception. When the innermost thing is a throw handler,
Guile calls the specified handler procedure using @code{(apply
@var{handler} key args)}. The handler procedure may either return
normally or exit non-locally. If it returns normally, Guile passes the
exception on to the next innermost @code{catch} or throw handler. If it
exits non-locally, that exit determines the continuation.
The behaviour of a throw handler is very similar to that of a
@code{catch} expression's optional pre-unwind handler. In particular, a
throw handler's handler procedure is invoked in the exact dynamic
context of the @code{throw} expression, just as a pre-unwind handler is.
@code{with-throw-handler} may be seen as a half-@code{catch}: it does
everything that a @code{catch} would do until the point where
@code{catch} would start unwinding the stack and dynamic context, but
then it rethrows to the next innermost @code{catch} or throw handler
instead.
Note also that since the dynamic context is not unwound, if a
@code{with-throw-handler} handler throws to a key that does not match
the @code{with-throw-handler} expression's @var{key}, the new throw may
be handled by a @code{catch} or throw handler that is @emph{closer} to
the throw than the first @code{with-throw-handler}.
Here is an example to illustrate this behavior:
@lisp
(catch 'a
(lambda ()
(with-throw-handler 'b
(lambda ()
(catch 'a
(lambda ()
(throw 'b))
inner-handler))
(lambda (key . args)
(throw 'a))))
outer-handler)
@end lisp
@noindent
This code will call @code{inner-handler} and then continue with the
continuation of the inner @code{catch}.
@node Throw
@subsubsection Throwing Exceptions
The @code{throw} primitive is used to throw an exception. One argument,
the @var{key}, is mandatory, and must be a symbol; it indicates the type
of exception that is being thrown. Following the @var{key},
@code{throw} accepts any number of additional arguments, whose meaning
depends on the exception type. The documentation for each possible type
of exception should specify the additional arguments that are expected
for that kind of exception.
@deffn {Scheme Procedure} throw key arg @dots{}
@deffnx {C Function} scm_throw (key, args)
Invoke the catch form matching @var{key}, passing @var{arg} @dots{} to
the @var{handler}.
@var{key} is a symbol. It will match catches of the same symbol or of
@code{#t}.
If there is no handler at all, Guile prints an error and then exits.
@end deffn
When an exception is thrown, it will be caught by the innermost
@code{catch} or throw handler that applies to the type of the thrown
exception; in other words, whose @var{key} is either @code{#t} or the
same symbol as that used in the @code{throw} expression. Once Guile has
identified the appropriate @code{catch} or throw handler, it handles the
exception by applying the relevant handler procedure(s) to the arguments
of the @code{throw}.
If there is no appropriate @code{catch} or throw handler for a thrown
exception, Guile prints an error to the current error port indicating an
uncaught exception, and then exits. In practice, it is quite difficult
to observe this behaviour, because Guile when used interactively
installs a top level @code{catch} handler that will catch all exceptions
and print an appropriate error message @emph{without} exiting. For
example, this is what happens if you try to throw an unhandled exception
in the standard Guile REPL; note that Guile's command loop continues
after the error message:
@lisp
guile> (throw 'badex)
<unnamed port>:3:1: In procedure gsubr-apply @dots{}
<unnamed port>:3:1: unhandled-exception: badex
ABORT: (misc-error)
guile>
@end lisp
The default uncaught exception behaviour can be observed by evaluating a
@code{throw} expression from the shell command line:
@example
$ guile -c "(begin (throw 'badex) (display \"here\\n\"))"
guile: uncaught throw to badex: ()
$
@end example
@noindent
That Guile exits immediately following the uncaught exception
is shown by the absence of any output from the @code{display}
expression, because Guile never gets to the point of evaluating that
expression.
@node Exception Implementation
@subsubsection How Guile Implements Exceptions
It is traditional in Scheme to implement exception systems using
@code{call-with-current-continuation}. Continuations
(@pxref{Continuations}) are such a powerful concept that any other
control mechanism --- including @code{catch} and @code{throw} --- can be
implemented in terms of them.
Guile does not implement @code{catch} and @code{throw} like this,
though. Why not? Because Guile is specifically designed to be easy to
integrate with applications written in C. In a mixed Scheme/C
environment, the concept of @dfn{continuation} must logically include
``what happens next'' in the C parts of the application as well as the
Scheme parts, and it turns out that the only reasonable way of
implementing continuations like this is to save and restore the complete
C stack.
So Guile's implementation of @code{call-with-current-continuation} is a
stack copying one. This allows it to interact well with ordinary C
code, but means that creating and calling a continuation is slowed down
by the time that it takes to copy the C stack.
The more targeted mechanism provided by @code{catch} and @code{throw}
does not need to save and restore the C stack because the @code{throw}
always jumps to a location higher up the stack of the code that executes
the @code{throw}. Therefore Guile implements the @code{catch} and
@code{throw} primitives independently of
@code{call-with-current-continuation}, in a way that takes advantage of
this @emph{upwards only} nature of exceptions.
@node Error Reporting
@subsection Procedures for Signaling Errors
@ -2023,8 +2157,13 @@ Guile's parameters conform to SRFI-39 (@pxref{SRFI-39}).
@node Handling Errors
@subsection How to Handle Errors
Error handling is based on @code{catch} and @code{throw}. Errors are
always thrown with a @var{key} and four arguments:
Guile is currently in a transition from its historical @code{catch} and
@code{throw} error handling and signaling operators to the new
structured exception facility; @xref{Exceptions}. However in the
meantime, here is some documentation on errors and the older
@code{catch} and @code{throw} interface.
Errors are always thrown with a @var{key} and four arguments:
@itemize @bullet
@item

View file

@ -356,8 +356,8 @@ library, or from Guile itself.
@menu
* Catching Exceptions:: Handling errors after the stack is unwound.
* Capturing Stacks:: Capturing the stack at the time of error.
* Pre-Unwind Debugging:: Debugging before the exception is thrown.
* Standard Error Handling:: Call-with-error-handling.
* Stack Overflow:: Detecting and handling runaway recursion.
* Debug Options:: A historical interface to debugging.
@end menu
@ -370,230 +370,64 @@ possible when a Scheme program hits an error. The most immediate
information about an error is the kind of error that it is -- such as
``division by zero'' -- and any parameters that the code which signalled
the error chose explicitly to provide. This information originates with
the @code{error} or @code{throw} call (or their C code equivalents, if
the error is detected by C code) that signals the error, and is passed
automatically to the handler procedure of the innermost applicable
@code{catch} or @code{with-throw-handler} expression.
the @code{error} or @code{raise-exception} call (or their C code
equivalents, if the error is detected by C code) that signals the error,
and is passed automatically to the handler procedure of the innermost
applicable exception handler.
Therefore, to catch errors that occur within a chunk of Scheme code, and
to intercept basic information about those errors, you need to execute
that code inside the dynamic context of a @code{catch} or
@code{with-throw-handler} expression, or the equivalent in C. In Scheme,
this means you need something like this:
@lisp
(catch #t
(lambda ()
;; Execute the code in which
;; you want to catch errors here.
...)
(lambda (key . parameters)
;; Put the code which you want
;; to handle an error here.
...))
@end lisp
@noindent
The @code{catch} here can also be @code{with-throw-handler}; see
@ref{Throw Handlers} for information on the when you might want to use
@code{with-throw-handler} instead of @code{catch}.
that code inside the dynamic context of a @code{with-exception-handler},
or the equivalent in C.
For example, to print out a message and return #f when an error occurs,
you might use:
@smalllisp
(define (catch-all thunk)
(catch #t
thunk
(lambda (key . parameters)
(with-exception-handler
(lambda (exn)
(format (current-error-port)
"Uncaught throw to '~a: ~a\n" key parameters)
#f)))
"Uncaught exception: ~s\n" exn)
#f)
thunk
#:unwind? #t))
(catch-all
(lambda () (error "Not a vegetable: tomato")))
@print{} Uncaught throw to 'misc-error: (#f ~A (Not a vegetable: tomato) #f)
@print{} Uncaught exception: #<&exception-with-kind-and-args ...>
@result{} #f
@end smalllisp
The @code{#t} means that the catch is applicable to all kinds of error.
If you want to restrict your catch to just one kind of error, you can
put the symbol for that kind of error instead of @code{#t}. The
equivalent to this in C would be something like this:
@xref{Exceptions}, for full details.
@lisp
SCM my_body_proc (void *body_data)
@{
/* Execute the code in which
you want to catch errors here. */
...
@}
SCM my_handler_proc (void *handler_data,
SCM key,
SCM parameters)
@{
/* Put the code which you want
to handle an error here. */
...
@}
@{
...
scm_c_catch (SCM_BOOL_T,
my_body_proc, body_data,
my_handler_proc, handler_data,
NULL, NULL);
...
@}
@end lisp
@noindent
Again, as with the Scheme version, @code{scm_c_catch} could be replaced
by @code{scm_c_with_throw_handler}, and @code{SCM_BOOL_T} could instead
be the symbol for a particular kind of error.
@node Capturing Stacks
@subsubsection Capturing the full error stack
The other interesting information about an error is the full Scheme
stack at the point where the error occurred; in other words what
innermost expression was being evaluated, what was the expression that
called that one, and so on. If you want to write your code so that it
captures and can display this information as well, there are a couple
important things to understand.
Firstly, the stack at the point of the error needs to be explicitly
captured by a @code{make-stack} call (or the C equivalent
@code{scm_make_stack}). The Guile library does not do this
``automatically'' for you, so you will need to write code with a
@code{make-stack} or @code{scm_make_stack} call yourself. (We emphasise
this point because some people are misled by the fact that the Guile
interactive REPL code @emph{does} capture and display the stack
automatically. But the Guile interactive REPL is itself a Scheme
program@footnote{In effect, it is the default program which is run when
no commands or script file are specified on the Guile command line.}
running on top of the Guile library, and which uses @code{catch} and
@code{make-stack} in the way we are about to describe to capture the
stack when an error occurs.)
And secondly, in order to capture the stack effectively at the point
where the error occurred, the @code{make-stack} call must be made before
Guile unwinds the stack back to the location of the prevailing catch
expression. This means that the @code{make-stack} call must be made
within the handler of a @code{with-throw-handler} expression, or the
optional "pre-unwind" handler of a @code{catch}. (For the full story of
how these alternatives differ from each other, see @ref{Exceptions}. The
main difference is that @code{catch} terminates the error, whereas
@code{with-throw-handler} only intercepts it temporarily and then allow
it to continue propagating up to the next innermost handler.)
So, here are some examples of how to do all this in Scheme and in C.
For the purpose of these examples we assume that the captured stack
should be stored in a variable, so that it can be displayed or
arbitrarily processed later on. In Scheme:
@lisp
(let ((captured-stack #f))
(catch #t
(lambda ()
;; Execute the code in which
;; you want to catch errors here.
...)
(lambda (key . parameters)
;; Put the code which you want
;; to handle an error after the
;; stack has been unwound here.
...)
(lambda (key . parameters)
;; Capture the stack here:
(set! captured-stack (make-stack #t))))
...
(if captured-stack
(begin
;; Display or process the captured stack.
...))
...)
@end lisp
@noindent
And in C:
@lisp
SCM my_body_proc (void *body_data)
@{
/* Execute the code in which
you want to catch errors here. */
...
@}
SCM my_handler_proc (void *handler_data,
SCM key,
SCM parameters)
@{
/* Put the code which you want
to handle an error after the
stack has been unwound here. */
...
@}
SCM my_preunwind_proc (void *handler_data,
SCM key,
SCM parameters)
@{
/* Capture the stack here: */
*(SCM *)handler_data = scm_make_stack (SCM_BOOL_T, SCM_EOL);
@}
@{
SCM captured_stack = SCM_BOOL_F;
...
scm_c_catch (SCM_BOOL_T,
my_body_proc, body_data,
my_handler_proc, handler_data,
my_preunwind_proc, &captured_stack);
...
if (captured_stack != SCM_BOOL_F)
@{
/* Display or process the captured stack. */
...
@}
...
@}
@end lisp
Once you have a captured stack, you can interrogate and display its
details in any way that you want, using the @code{stack-@dots{}} and
@code{frame-@dots{}} API described in @ref{Stacks} and
@ref{Frames}.
If you want to print out a backtrace in the same format that the Guile
REPL does, you can use the @code{display-backtrace} procedure to do so.
You can also use @code{display-application} to display an individual
frame in the Guile REPL format.
@node Pre-Unwind Debugging
@subsubsection Pre-Unwind Debugging
Instead of saving a stack away and waiting for the @code{catch} to
return, you can handle errors directly, from within the pre-unwind
handler.
Sometimes when something goes wrong, what you want is not just a
representation of the exceptional situation, but the context that
brought about that situation. The example in the previous section
passed @code{#:unwind #t} to @code{with-exception-handler}, indicating
that @code{raise-exception} should unwind the stack before invoking the
exception handler. However if you don't take this approach and instead
let the exception handler be invoked in the context of the
@code{raise-exception}, you can print a backtrace, launch a recursive
debugger, or take other ``pre-unwind'' actions.
For example, to show a backtrace when an error is thrown, you might want
to use a procedure like this:
The most basic idea would be to simply print a backtrace:
@lisp
(define (with-backtrace thunk)
(with-throw-handler #t
thunk
(lambda args (backtrace))))
(with-backtrace (lambda () (error "Not a vegetable: tomato")))
@end lisp
@example
(define (call-with-backtrace thunk)
(with-exception-handler
(lambda (exn)
(backtrace)
(raise-exception exn))
thunk))
@end example
Since we used @code{with-throw-handler} here, we didn't actually catch
the error. @xref{Throw Handlers}, for more information. However, we did
print out a context at the time of the error, using the built-in
procedure, @code{backtrace}.
Here we use the built-in @code{backtrace} procedure to print the
backtrace.
@deffn {Scheme Procedure} backtrace [highlights]
@deffnx {C Function} scm_backtrace_with_highlights (highlights)
@ -603,6 +437,47 @@ Display a backtrace of the current stack to the current output port. If
will be highlighted wherever they appear in the backtrace.
@end deffn
By re-raising the exception, @code{call-with-backtrace} doesn't actually
handle the error. We could define a version that instead aborts the
computation:
@example
(use-modules (ice-9 control))
(define (call-with-backtrace thunk)
(let/ec cancel
(with-exception-handler
(lambda (exn)
(backtrace)
(cancel #f))
thunk)))
@end example
In this second example, we use an escape continuation to abort the
computation after printing the backtrace, returning @code{#f} instead.
It could be that you want to only print a limited backtrace. In that
case, use @code{start-stack}:
@example
(use-modules (ice-9 control))
(define (call-with-backtrace thunk)
(let/ec cancel
(start-stack 'stack-with-backtrace
(with-exception-handler
(lambda (exn)
(backtrace)
(cancel #f))
thunk))))
@end example
There are also more powerful, programmatic ways to walk the stack using
@code{make-stack} and friends; see the API described in @ref{Stacks} and
@ref{Frames}.
@node Standard Error Handling
@subsubsection call-with-error-handling
The Guile REPL code (in @file{system/repl/repl.scm} and related files)
uses a @code{catch} with a pre-unwind handler to capture the stack when
an error occurs in an expression that was typed into the REPL, and debug
@ -622,6 +497,12 @@ These procedures are available for use by user programs, in the
[#:trap-handler trap-handler='debug]
Call a thunk in a context in which errors are handled.
Note that this function was written when @code{throw}/@code{catch} were
the fundamental exception handling primitives in Guile, and so exposes
some aspects of that interface (notably in the form of the procedural
handlers). Guile will probably replace this function with a
@code{call-with-standard-exception-handling} in the future.
There are five keyword arguments:
@table @var
@ -743,11 +624,11 @@ on @var{l}, not @code{(cdr @var{l})}. Running this program would cause
Guile to use up all memory in your system, and eventually Guile would
fail to grow the stack. At that point you have a problem: Guile needs
to raise an exception to unwind the stack and return memory to the
system, but the user might have throw handlers in place (@pxref{Throw
Handlers}) that want to run before the stack is unwound, and we don't
have any stack in which to run them.
system, but the user might have exception handlers in place
(@pxref{Raising and Handling Exceptions}) that want to run before the
stack is unwound, and we don't have any stack in which to run them.
Therefore in this case, Guile throws an unwind-only exception that does
Therefore in this case, Guile raises an unwind-only exception that does
not run pre-unwind handlers. Because this is such an odd case, Guile
prints out a message on the console, in case the user was expecting to
be able to get a backtrace from any pre-unwind handler.

View file

@ -473,8 +473,8 @@ interrupts. What happens if you hold a mutex, but somehow you cause an
exception to be thrown? There is no one right answer. You might want
to keep the mutex locked to prevent any other code from ever entering
that critical section again. Or, your critical section might be fine if
you unlock the mutex ``on the way out'', via a catch handler or
@code{dynamic-wind}. @xref{Catch}, and @xref{Dynamic Wind}.
you unlock the mutex ``on the way out'', via an exception handler or
@code{dynamic-wind}. @xref{Exceptions}, and @xref{Dynamic Wind}.
But if you arrange to unlock the mutex when leaving a dynamic extent via
@code{dynamic-wind}, what to do if control re-enters that dynamic extent

View file

@ -1139,38 +1139,16 @@ descriptor @var{rtd} (and not any of its sub- or supertypes) is mutable.
@subsubsection rnrs exceptions
The @code{(rnrs exceptions (6))} library provides functionality related
to signaling and handling exceptional situations. This functionality is
similar to the exception handling systems provided by Guile's core
library @xref{Exceptions}, and by the SRFI-18 and SRFI-34
modules---@xref{SRFI-18 Exceptions}, and @ref{SRFI-34},
respectively---but there are some key differences in concepts and
behavior.
A raised exception may be @dfn{continuable} or @dfn{non-continuable}.
When an exception is raised non-continuably, another exception, with the
condition type @code{&non-continuable}, will be raised when the
exception handler returns locally. Raising an exception continuably
captures the current continuation and invokes it after a local return
from the exception handler.
Like SRFI-18 and SRFI-34, R6RS exceptions are implemented on top of
Guile's native @code{throw} and @code{catch} forms, and use custom
``throw keys'' to identify their exception types. As a consequence,
Guile's @code{catch} form can handle exceptions thrown by these APIs,
but the reverse is not true: Handlers registered by the
@code{with-exception-handler} procedure described below will only be
called on exceptions thrown by the corresponding @code{raise} procedure.
to signaling and handling exceptional situations. This functionality
re-exports Guile's core exception-handling primitives.
@xref{Exceptions}, for a full discussion. @xref{SRFI-34}, for a similar
pre-R6RS facility. In Guile, SRFI-34, SRFI-35, and R6RS exception
handling are all built on the same core facilities, and so are
interoperable.
@deffn {Scheme Procedure} with-exception-handler handler thunk
Installs @var{handler}, which must be a procedure taking one argument,
as the current exception handler during the invocation of @var{thunk}, a
procedure taking zero arguments. The handler in place at the time
@code{with-exception-handler} is called is made current again once
either @var{thunk} returns or @var{handler} is invoked after an
exception is thrown from within @var{thunk}.
This procedure is similar to the @code{with-throw-handler} procedure
provided by Guile's code library; (@pxref{Throw Handlers}).
@xref{Raising and Handling Exceptions}, for more information on
@code{with-exception-handler}.
@end deffn
@deffn {Scheme Syntax} guard (variable clause1 clause2 ...) body
@ -1194,17 +1172,18 @@ evaluates to @code{baz}.
@end deffn
@deffn {Scheme Procedure} raise obj
Raises a non-continuable exception by invoking the currently-installed
exception handler on @var{obj}. If the handler returns, a
@code{&non-continuable} exception will be raised in the dynamic context
in which the handler was installed.
Equivalent to core Guile @code{(raise-exception @var{obj})}.
@xref{Raising and Handling Exceptions}. p(Unfortunately, @code{raise}
is already bound to a different function in core Guile.
@xref{Signals}.)
@end deffn
@deffn {Scheme Procedure} raise-continuable obj
Raises a continuable exception by invoking currently-installed exception
handler on @var{obj}.
Equivalent to core Guile @code{(raise-exception @var{obj} #:continuable?
#t)}. @xref{Raising and Handling Exceptions}.
@end deffn
@node rnrs conditions
@subsubsection rnrs conditions
@ -1232,17 +1211,26 @@ component simple condition of the appropriate type; the field accessors
return the requisite fields from the first component simple condition
found to be of the appropriate type.
Guile's R6RS layer uses core exception types from the @code{(ice-9
exceptions)} module as the basis for its R6RS condition system. Guile
prefers to use the term ``exception object'' and ``exception type''
rather than ``condition'' or ``condition type'', but that's just a
naming difference. Guile also has different names for the types in the
condition hierarchy. @xref{Exception Objects}, for full details.
This library is quite similar to the SRFI-35 conditions module
(@pxref{SRFI-35}). Among other minor differences, the
@code{(rnrs conditions)} library features slightly different semantics
around condition field accessors, and comes with a larger number of
pre-defined condition types. The two APIs are not currently compatible,
however; the @code{condition?} predicate from one API will return
@code{#f} when applied to a condition object created in the other.
(@pxref{SRFI-35}). Among other minor differences, the @code{(rnrs
conditions)} library features slightly different semantics around
condition field accessors, and comes with a larger number of pre-defined
condition types. The two APIs are compatible; the @code{condition?}
predicate from one API will return @code{#t} when applied to a condition
object created in the other. of the condition types are the same,
also.
@deffn {Condition Type} &condition
@deffnx {Scheme Procedure} condition? obj
The base record type for conditions.
The base record type for conditions. Known as @code{&exception} in core
Guile.
@end deffn
@deffn {Scheme Procedure} condition condition1 ...
@ -1294,27 +1282,29 @@ A base type for representing non-fatal conditions during execution.
@deffnx {Scheme Procedure} make-serious-condition
@deffnx {Scheme Procedure} serious-condition? obj
A base type for conditions representing errors serious enough that
cannot be ignored.
cannot be ignored. Known as @code{&error} in core Guile.
@end deffn
@deffn {Condition Type} &error
@deffnx {Scheme Procedure} make-error
@deffnx {Scheme Procedure} error? obj
A base type for conditions representing errors.
A base type for conditions representing errors. Known as
@code{&external-error} in core Guile.
@end deffn
@deffn {Condition Type} &violation
@deffnx {Scheme Procedure} make-violation
@deffnx {Scheme Procedure} violation?
A subtype of @code{&serious} that can be used to represent violations
of a language or library standard.
A subtype of @code{&serious} that can be used to represent violations of
a language or library standard. Known as @code{&programming-error} in
core Guile.
@end deffn
@deffn {Condition Type} &assertion
@deffnx {Scheme Procedure} make-assertion-violation
@deffnx {Scheme Procedure} assertion-violation? obj
A subtype of @code{&violation} that indicates an invalid call to a
procedure.
procedure. Known as @code{&assertion-failure} in core Guile.
@end deffn
@deffn {Condition Type} &irritants
@ -1368,7 +1358,7 @@ indicate the syntactic form responsible for the condition.
@deffnx {Scheme Procedure} make-undefined-violation
@deffnx {Scheme Procedure} undefined-violation? obj
A subtype of @code{&violation} that indicates a reference to an unbound
identifier.
identifier. Known as @code{&undefined-variable} in core Guile.
@end deffn
@node R6RS I/O Conditions

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018
@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018, 2019
@c Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@ -3320,7 +3320,26 @@ handling mechanisms} as an alternative to its own built-in mechanisms
(use-modules (srfi srfi-34))
@end lisp
@c FIXME: Document it.
@xref{Raising and Handling Exceptions}, for more on
@code{with-exception-handler} and @code{raise} (known as
@code{raise-exception} in core Guile).
SRFI-34's @code{guard} form is syntactic sugar over
@code{with-exception-handler}:
@deffn {Syntax} guard (var clause @dots{}) body @dots{}
Evaluate @var{body} with an exception handler that binds the raised
object to @var{var} and within the scope of that binding evaluates
@var{clause}@dots{} as if they were the clauses of a cond expression.
That implicit cond expression is evaluated with the continuation and
dynamic environment of the guard expression.
If every @var{clause}'s test evaluates to false and there is no
@code{else} clause, then @code{raise} is re-invoked on the raised object
within the dynamic environment of the original call to @code{raise}
except that the current exception handler is that of the @code{guard}
expression.
@end deffn
@node SRFI-35
@ -3330,7 +3349,7 @@ handling mechanisms} as an alternative to its own built-in mechanisms
@cindex conditions
@cindex exceptions
@uref{http://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35} implements
@uref{http://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35} defines
@dfn{conditions}, a data structure akin to records designed to convey
information about exceptional conditions between parts of a program. It
is normally used in conjunction with SRFI-34's @code{raise}:
@ -3498,6 +3517,12 @@ the user.
Return true if @var{c} is of type @code{&error} or one of its subtypes.
@end deffn
As an implementation note, condition objects in Guile are the same as
``exception objects''. @xref{Exception Objects}. The
@code{&condition}, @code{&serious}, and @code{&error} condition types
are known in core Guile as @code{&exception}, @code{&error}, and
@code{&external-error}, respectively.
@node SRFI-37
@subsection SRFI-37 - args-fold
@cindex SRFI-37