guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 02/02: Update documentation for with-exception-handler e


From: Andy Wingo
Subject: [Guile-commits] 02/02: Update documentation for with-exception-handler et al
Date: Wed, 13 Nov 2019 16:33:26 -0500 (EST)

wingo pushed a commit to branch wip-exceptions
in repository guile.

commit 44ee8c5559ed2f30df464ba1bffdae24994291b3
Author: Andy Wingo <address@hidden>
Date:   Wed Nov 13 22:26:31 2019 +0100

    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.
---
 doc/ref/api-control.texi    | 813 ++++++++++++++++++++++++++------------------
 doc/ref/api-debug.texi      | 291 +++++-----------
 doc/ref/api-scheduling.texi |   4 +-
 doc/ref/r6rs.texi           |  88 +++--
 doc/ref/srfi-modules.texi   |  31 +-
 5 files changed, 631 insertions(+), 596 deletions(-)

diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi
index c0d1c18..f603e32 100644
--- a/doc/ref/api-control.texi
+++ b/doc/ref/api-control.texi
@@ -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,298 +1025,423 @@ 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.
 
-@node Catch
-@subsubsection Catching Exceptions
+@deffn {Scheme Procedure} make-exception exceptions @dots{}
+Return an exception object composed of @var{exceptions}.
+@end deffn
 
-@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.
+@deffn {Scheme Procedure} exception? obj
+Return true if @var{obj} is an exception object.
+@end deffn
 
-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} 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
 
-@lisp
-(/ 1 0)
-@result{}
-ABORT: (numerical-overflow)
-@end lisp
+@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
 
-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.
-
-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.
-
-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}.
-
-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}.
+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:
 
-@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
+@example
+(use-modules (ice-9 exceptions))
+@end example
 
-@var{key} is a symbol or @code{#t}.
+The following diagram gives an overview of the standard exception type
+hierarchy.
 
-@var{thunk} takes no arguments.  If @var{thunk} returns
-normally, that is the return value of @code{catch}.
+@example
+&exception
+|- &warning
+|- &message
+|- &irritants
+|- &origin
+\- &error
+   |- &external-error
+   \- &programming-error
+      |- &assertion-failure
+      |- &non-continuable
+      |- &implementation-restriction
+      |- &lexical
+      |- &syntax
+      \- &undefined-variable
+@end example
 
-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.
+@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
 
-If the key is @code{#t}, then a throw to @emph{any} symbol will
-match this call to @code{catch}.
+@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
 
-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.
+@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
 
-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.
+@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
 
-If a handler procedure needs to match a variety of @code{throw}
-expressions with varying numbers of arguments, you should write it like
-this:
+@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
 
-@lisp
-(lambda (key . args)
-  @dots{})
-@end lisp
+@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
 
-@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.
-
-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.
+@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
 
-@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}
-take Scheme procedures as body and handler arguments.
-@code{scm_c_catch} and @code{scm_internal_catch} are equivalents taking
-C functions.
+@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
 
-@var{body} is called as @code{@var{body} (@var{body_data})} with a catch
-on exceptions of the given @var{tag} type.  If an exception is caught,
-@var{pre_unwind_handler} and @var{handler} are called as
-@code{@var{handler} (@var{handler_data}, @var{key}, @var{args})}.
-@var{key} and @var{args} are the @code{SCM} key and argument list from
-the @code{throw}.
+@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
 
-@tpindex scm_t_catch_body
-@tpindex scm_t_catch_handler
-@var{body} and @var{handler} should have the following prototypes.
-@code{scm_t_catch_body} and @code{scm_t_catch_handler} are pointer
-typedefs for these.
+@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
 
-@example
-SCM body (void *data);
-SCM handler (void *data, SCM key, SCM args);
-@end example
+@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
 
-The @var{body_data} and @var{handler_data} parameters are passed to
-the respective calls so an application can communicate extra
-information to those functions.
+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
 
-If the data consists of an @code{SCM} object, care should be taken that
-it isn't garbage collected while still required.  If the @code{SCM} is a
-local C variable, one way to protect it is to pass a pointer to that
-variable as the data parameter, since the C compiler will then know the
-value must be held on the stack.  Another way is to use
-@code{scm_remember_upto_here_1} (@pxref{Foreign Object Memory
-Management}).
-@end deftypefn
 
+@node Raising and Handling Exceptions
+@subsubsection Raising and Handling Exceptions
 
-@node Throw Handlers
-@subsubsection Throw Handlers
+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.
 
-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} 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.
 
-@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}.
+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
+
+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.
 
-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.
+To establish an exception handler within the dynamic extent of a call,
+use @code{with-exception-handler}.
+
+@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}.
+
+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
 
-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.
+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}.
 
-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,
+@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)
+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}.
+
+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
 
-@lisp
-(with-throw-handler 'key
-  (lambda () @dots{} (throw 'key args @dots{}) @dots{})
-  handler)
-@end lisp
+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:
 
-@noindent
-is mostly equivalent to
+@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
 
-@lisp
-((lambda () @dots{} (handler 'key args @dots{}) @dots{}))
-@end lisp
+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.
 
-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}.)
+If @code{catch} is called with four arguments, then the use of
+@var{thunk} should be replaced with:
 
-@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}.
-@end deftypefn
+@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.
 
-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}.
+@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
@@ -1328,101 +1462,101 @@ Here is an example to illustrate this behavior:
 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.
+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)
-Invoke the catch form matching @var{key}, passing @var{arg} @dots{} to
-the @var{handler}.
+Raise an exception with kind @var{key} and arguments @var{args}.
+@var{key} is a symbol, denoting the ``kind'' of the exception.
+@end deffn
 
-@var{key} is a symbol.  It will match catches of the same symbol or of
-@code{#t}.
+Again, we can specify what @code{throw} does by expressing it in terms
+of @code{raise-exception}.
 
-If there is no handler at all, Guile prints an error and then exits.
+@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
 
-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}.
+@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
 
-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:
+@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
 
-@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:
+@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.
+
+@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}
+take Scheme procedures as body and handler arguments.
+@code{scm_c_catch} and @code{scm_internal_catch} are equivalents taking
+C functions.
+
+@var{body} is called as @code{@var{body} (@var{body_data})} with a catch
+on exceptions of the given @var{tag} type.  If an exception is caught,
+@var{pre_unwind_handler} and @var{handler} are called as
+@code{@var{handler} (@var{handler_data}, @var{key}, @var{args})}.
+@var{key} and @var{args} are the @code{SCM} key and argument list from
+the @code{throw}.
+
+@tpindex scm_t_catch_body
+@tpindex scm_t_catch_handler
+@var{body} and @var{handler} should have the following prototypes.
+@code{scm_t_catch_body} and @code{scm_t_catch_handler} are pointer
+typedefs for these.
 
 @example
-$ guile -c "(begin (throw 'badex) (display \"here\\n\"))"
-guile: uncaught throw to badex: ()
-$ 
+SCM body (void *data);
+SCM handler (void *data, SCM key, SCM args);
 @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.
+The @var{body_data} and @var{handler_data} parameters are passed to
+the respective calls so an application can communicate extra
+information to those functions.
+
+If the data consists of an @code{SCM} object, care should be taken that
+it isn't garbage collected while still required.  If the @code{SCM} is a
+local C variable, one way to protect it is to pass a pointer to that
+variable as the data parameter, since the C compiler will then know the
+value must be held on the stack.  Another way is to use
+@code{scm_remember_upto_here_1} (@pxref{Foreign Object Memory
+Management}).
+@end deftypefn
+
+@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{Exceptions and C}) for a description of the parameters, the
+behaviour however of course follows @code{with-throw-handler}.
+@end deftypefn
 
 
 @node Error Reporting
@@ -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
diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi
index 4fc295d..d7d0412 100644
--- a/doc/ref/api-debug.texi
+++ b/doc/ref/api-debug.texi
@@ -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.
diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi
index 7b39a03..413a213 100644
--- a/doc/ref/api-scheduling.texi
+++ b/doc/ref/api-scheduling.texi
@@ -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
diff --git a/doc/ref/r6rs.texi b/doc/ref/r6rs.texi
index 436f7c8..66c8690 100644
--- a/doc/ref/r6rs.texi
+++ b/doc/ref/r6rs.texi
@@ -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
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 58548a3..7d36f0f 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]