Gauche’s exception system consists of three components; (1) the way to signal an exceptional case has occurred, (2) the way to specify how to handle such a case, and (3) the standard objects (conditions) to communicate the code that signals an exceptional case and the code that handles it.
Those three components are typically used together, so first we explain the typical usage patterns using examples. Then we describe each feature in detail.
Note for terminology: some languages use the word exception to refer to an object used to communicate the code that encountered an exceptional situation with a handler that deals with it. Gauche uses a term condition to refer to such objects, following SRFI-35. Exception is the situation, and condition is a runtime object that describes it.
• Exception handling overview: | ||
• Signaling exceptions: | ||
• Handling exceptions: | ||
• Conditions: |
One of the most typical exception handling is to catch a
specific error raised by some built-in or library procedures.
A macro guard
can be used for such a purpose. The code
looks like this:
(guard (exc [(condition-has-type? exc <read-error>) (format #t "read error!") 'read-error] [else 'other-error]) (read-from-string "(abc"))
The cadr of guard
clause is a form of
(variable clause …)
. In this example,
the variable is exc
, and it has two clauses.
Each clause has the form like the one in cond
.
The cddr of guard
is the body, a list of expressions. This
example has only one expression, (read-from-string "(abc")
.
guard
starts executing its body.
read-from-string
raises an error of type <read-error>
when it encounters syntactic errors. The form guard
intercepts
the error, and binds the condition object to the variable exc,
then checks the clauses following exc in a similar manner
to cond
—in this case, the thrown condition is of type
<read-error>
, so the test of the first clause is satisfied,
and the rest of clause is executed, i.e. "read error!"
is
printed and a symbol read-error
is returned.
If you’re familiar with other languages, you may recognize the
pattern. The cddr of guard
form is like try clause
of C++/Java or the cadr of handler-case
of Common Lisp;
and the cdadr of guard
form is like catch
clauses
or the cddr of handler-case
.
In the test expressions it is common to check the type of
thrown condition. The function condition-has-type?
is
defined in SRFI-35 but it’s rather lengthy. Gauche’s condition
classes can also work like a predicate, so you can write the
above expression like this.
(guard (exc [(<read-error> exc) (format #t "read error!") 'read-error] [else 'other-error]) (read-from-string "(abc"))
Note: Generally you can’t use is-a?
to test if
the thrown condition is of a specific type, since a condition
may be compound. See Conditions about compound
conditions.
If no tests of clauses satisfy and no else
clause is given,
the exception ‘falls off’ the guard
construct, i.e.
it will be handled by the outer level of guard
form or
top-level. For example, the following guard
form
only handles <read-error>
and <system-error>
;
if the body throws other type of conditions, it must be handled
by outer level.
(guard (exc [(<read-error> exc) (handle-read-error)] [(<system-error> exc) (handle-system-error)]) body ...)
See Handling exceptions for more details on guard
and
other lower-level exception handling constructs.
The generic way to signal an exception is to use raise
procedure.
(raise condition)
You can pass any object to condition; its interpretation
solely depends on the exception handler. If you know the code
raises an integer as a condition, you can catch it by guard
as this:
(guard (exc [(integer? exc) 'raised]) (raise 3))
However, as a convention, it is preferable to use an instance
of <condition>
or one of its subclasses. A macro condition
can be used to create a condition object. The following examples
show how to create a condition with some slot values and then raise it.
;; create and raise an error condition (raise (condition (<error> (message "An error occurred.")))) ;; create and raise a system error condition (raise (condition (<system-error> (message "A system error occurred.") (errno EINTR))))
See Conditions for the details of condition
macro
and what kind of condition classes are provided.
The most common type of condition is an error condition, so
a convenience procedure error
and errorf
are
provided. They create an error condition with a message and
raise it.
;; `error' concatenates the arguments into a message. (unless (integer? obj) (error "Integer expected, but got:" obj)) ;; `errorf' uses format to create a message. (unless (equal? x y) (errorf "~s and ~s don't match" x y))
Unlike the exception throwing constructs in some languages,
such as throw
of C++/Java, which abandons its continuation,
Scheme’s raise
may return to its caller. If you don’t
want raise
to return, a rule of thumb is always to pass
one of error conditions to it; then Gauche guarantees raise
wont return. See the description of raise
in
Signaling exceptions for more details.
Note: R7RS adopted slightly different semantics; it splits
raise
and raise-continuable
, the former is for
noncontinuable exception (if the exception handler returns,
it raises another error), and the latter is for continuable
exception. When you’re in R7RS environment, R7RS-compatible
raise
will be used instead of this raise
.
You can also define your own condition classes to pass application-specific information from the point of raising exception to the handlers.
To fit to Gauche’s framework (SRFI-35), it is desirable that
the new condition class inherits a built-in <condition>
class
or one of its descendants, and also is an instance of a metaclass
<condition-meta>
.
One way of ensuring the above convention as well as increasing
portability is to use define-condition-type
macro, defined
in srfi.35
.
(define-condition-type <myapp-error> <error> myapp-error? (debug-info myapp-error-debug-info) (reason myapp-error-reason))
This defines a condition type (which is a class in Gauche)
<myapp-error>
, with a predicate myapp-error?
and slots with accessors. Then you can use the new
condition type like the following code:
(guard (exc [(myapp-error? exc) (let ([debug-info (myapp-error-debug-info exc)] [reason (myapp-error-reason exc)]) ... handle myapp-error ...)]) ... ... (if (something-went-wrong) (raise (condition (<myapp-error> (debug-info "during processing xxx") (reason "something went wrong"))))) ... ... )
If you don’t mind to lose srfi compatibility, you can use
Gauche’s extended error
and errorf
procedures to write
more concise code to raise a condition of subtype of <error>
:
(if (something-went-wrong) (error <myapp-error> :debug-info "during processing xxx" :reason "something went wrong"))
See the description of define-condition-type
macro
for how the condition type is implemented in Gauche’s object system.
The most common case of exceptions is an error.
Two convenience functions to signal an error condition
in simple cases are provided.
To signal a compound condition, you can use raise
as explained below.
[R7RS+ base][SRFI-23+]
Signals an error. The first form creates an <error>
condition, with a message consists of string and arg …,
and raises it. It is compatible to R7RS and SRFI-23’s error
behavior.
gosh> (define (check-integer x) (unless (integer? x) (error "Integer required, but got:" x))) check-integer gosh> (check-integer "a") *** ERROR: Integer required, but got: "a" Stack Trace: _______________________________________
The second form can be used to raise an error other than the
<error>
condition. condition-type must be
a condition type (see Conditions for more explanation of
condition types). It may be followed by keyword-value list
to initialize the condition slots, and then optionally followed by
a string and other objects that becomes an error message.
(define-condition-type <my-error> <error> #f (reason) (priority)) ... (unless (memq operation *supported-operations*) (error <my-error> :reason 'not-supported :priority 'urgent "Operation not supported:" operation)) ...
Similar to error
, but the error message is formatted by
format
, i.e. the first form is equivalent to:
(define (errorf fmt . args) (error (apply format #f fmt args)))
The second form can be used to raise an error other than an
<error>
condition. Meaning of condition-type and
keyword-args are the same as error
.
[SRFI-18][R7RS base] This is the base mechanism of signaling exceptions.
The procedure invokes the current exception handler.
The argument condition represents the nature of the exception,
and passed to the exception handler.
Gauche’s built-in and library functions always use
an instance of <condition>
or one of its subclasses as condition,
but you can pass any Scheme object to raise
. The interpretation
of condition is up to the exception handler.
Note: Unlike some of the mainstream languages in which
"throwing" an exception never returns, you can set up an exception
handler in the way that raise
may return. The details
are explained in Handling exceptions.
If you don’t want raise
to return, the best way is to
pass a condition which is an instance of <serious-condition>
or one of its subclasses. Gauche’s internal mechanism
guarantees raising such an exception won’t return.
See Conditions for the hierarchy of built-in conditions.
R7RS adopted slightly different semantics regarding returning from
raise
; in R7RS, raise
never returns—if the exception
handler returns, another exception is raised.
R7RS has raise-continuable
to explicitly allow returning from
the exception handler. For portable programs, always
pass <serious-condition>
or its subclasses to raise
.
• High-level exception handling mechanism: | ||
• Behavior of unhandled exception: | ||
• Low-level exception handling mechanism: |
[R7RS base] This is the high-level form to handle errors in Gauche.
var is a symbol, and clauses are the same form as
cond
’s clauses, i.e. each clause can be either one of
the following forms:
(test expr …)
(test => proc)
The last clause may be (else expr …)
.
This form evaluates body … and returns the value(s) of the last body expression in normal case. If an exception is raised during the evaluation of body expressions, the raised exception is bound to a variable var, then evaluates test expression of each clause. If one of test expressions returns true value, then the corresponding exprs are evaluated if the clause is the first form above, or an proc is evaluated and the result of test is passed to the procedure proc if the clause is the second form.
When the test(s) and expr(s) in the clauses are evaluated,
the exception handler that is in effect of the caller of guard
are
installed; that is, if an exception is raised again within clauses,
it is handled by the outer exception handler or guard
form.
If no test returns true value and the last clause
is
else
clause, then the associated exprs are evaluated.
If no test returns true value and there’s no else
clause,
the raised exception is re-raised, to be handled by the outer exception
handler.
When the exception is handled by one of clause
s, guard
returns the value(s) of the last expr in the handling clause.
The clauses are evaluated in the same dynamic environment as
the guard
form, i.e. any dynamic-wind
s inside body
are unwound before evaluation of the clauses. It is different
from the lower level forms
with-error-handler
and with-exception-handler
, whose
handler is evaluated before the dynamic environment are unwound.
(let ([z '()]) (guard (e [else (push! z 'caught)]) (dynamic-wind (lambda () (push! z 'pre)) (lambda () (error "foo")) (lambda () (push! z 'post)))) (reverse z)) ⇒ (pre post caught) (guard (e [else (print 'OUTER) #f]) (with-output-to-string (lambda () (print 'INNER) (error "foo")))) ⇒ prints OUTER to the current output port of guard, not to the string port.
Executes expr, then executes cleanups, and
returns the result(s) of expr. If an uncontinuable exception is raised
within expr, cleanups are executed before the
exception escapes from the unwind-protect
form.
For example, the following code calls start-motor
,
drill-a-hole
, and stop-motor
in order if
everything goes ok, and if anything goes wrong in start-motor
or drill-a-hole
, stop-motor
is still called
before the exception escapes unwind-protect
.
(unwind-protect (begin (start-motor) (drill-a-hole)) (stop-motor))
The cleanup forms are evaluated in the same dynamic environment
as unwind-protect
.
If an exception is thrown within cleanup, it will be
handled outside of the unwind-protect
form.
Although this form looks similar to dynamic-wind
, they
work at different layers and should not be confused.
dynamic-wind
is the bottom-level
building block and used to manage current exception handlers,
current i/o ports, parameters, etc.
dynamic-wind
’s before and after thunks are
called whenever any of those control flow transition occurs.
On the other hand, unwind-protect
only cares about
the Gauche’s exception system. unwind-protect
’s cleanup
is called only when expr exits normally or
throws Gauche’s exception.
In the above example, if control escapes from drill-a-hole
by calling a continuation captured outside of unwind-protect
,
cleanup is not called; because the control may return to
drill-a-hole
again. It can happen if user-level thread
system is implemented by call/cc
, for example.
You can go back to the body expr
from outside of unwind-protect
by invoking continuations
captured within expr.
However, keep in mind that once cleanup are executed, some resources might not be available in expr. We still allow it since the reexecuted part of expr may not depend on the resources cleaned up with cleanup.
Even if expr returns (normally or abnormally), cleanup only executed once, in the first time.
The name of this form is taken from Common Lisp. Some Scheme
systems have similar macros in different names, such as
try-finally
.
Makes handler the active error handler and executes thunk.
If thunk returns normally, the result(s) will be returned.
If an error is signaled during execution of thunk,
handler is called with one argument, an exception object
representing the error, with the continuation of with-error-handler
.
That is, with-error-handler
returns whatever value(s) handler
returns.
If handler signals an error, it will be handled by the
handler installed when with-error-handler
called.
The dynamic environment where handler is executed is
the same as the error occurs. If dynamic-wind
is used
in thunk, its after method is called after handler
has returned, and before with-error-handler
returns.
Note: Using this procedure directly is no longer recommended, since
guard
is more safe and portable. We’ll keep this for
a while for the backward compatibility, but we recommend to rewrite
code to use guard
instead of this.
The common idiom of "cleanup on error"
code:
(with-error-handler (lambda (e) (cleanup) (raise e)) (lambda () body ...))
should be written like this:
(guard (e [else (cleanup) (raise e)]) body ...)
If an exception is raised where no program-defined exception handler is installed, the following action is taken.
<uncaught-exception>
condition and stored in the
thread object. If other thread calls thread-join!
to retrieve
result, the the <uncaught-exception>
is thrown in that thread.
Note that no messages are displayed when the original uncaught exception
is thrown. See Thread programming tips, for the details.
EX_SOFTWARE
(70).
The default error message and stack trace in the above case 2 and case 3
is printed by report-error
procedure. You can use it
in your error handler if you need the same information.
Prints type and message of a thrown condition object exn, then print the current stack trace. This is the procedure the system calls when you see an error reported on REPL.
Since you can raise
any object, exn can be any
object; it’s not needed to be an instance of <condition>
.
A suitable message is chosen by report-error
.
You can specify where the output goes by the optional sink
argument: If it is an output port, the output goes there; you can
also pass #t
for the current output port and #f
for
the output string port, just like format
. That is, when
you pass #f
, the message goes to a temporary output string
port, and gathered string is returned. For all the other cases,
an undefined value is returned. If sink is omitted or
any other object listed above, the current error port is used.
Internally, this procedure calls print-default-error-heading
and print-additional-error-heading
to print the info about exn, then prints the stack trace.
You can call those procedures separately if you don’t want
the stack trace.
Note: As of 0.9.5, this procedure prints stack trace of
the context where report-error
is called, rather than
the context where exn is thrown. It doesn’t matter much
as far as you call report-error
directly inside the
error handler, but in general what
you want to print is the latter, and we have a plan to
attach stack trace info to <condition>
object in future.
Prints the first line of the default error report regarding the thrown condition exn to an output port out.
If exn is a <condition>
, the message
consists of the condition class name (without brackets, and capitalized),
followed by the message of the condition:
*** READ-ERROR: Read error at "foo":line 1: EOF inside a list (starting from line 1)
If exn is not a <condition>
, it assumes that the exception is
intended to be caught but somehow escaped, so it prints something
like this:
*** ERROR: unhandled exception: foo
This is called by report-error
, but you can use this procedure
separately.
Prints the additional information of the thrown condition exn to an output port out.
If exn is not a <condition>
, no information is printed.
If exn is a compound condition, it is decomposed into individual conditions.
Then, for each condition that does not inherit <mixin-condition>
,
report-additional-condition
method is invoked on it.
Afterwards,
for each of the remaining conditions (those inherit <mixin-condition>
),
report-additional-condition
method is invoked on it.
For example, when you see the following error report:
*** UNBOUND-VARIABLE-ERROR: unbound variable: load NOTE: `load' is exported from the following modules: - scheme.r5rs - scheme.load While loading "/home/shiro/src/Gauche/src/../src/ttt.scm" at line 3 While compiling "./tttt.scm" at line 1: (use ttt) While loading "./tttt.scm" at line 1
***
) is printed by
print-default-error-heading
. The rest is printed
by print-additional-error-heading
.
<unbound-variable-error>
, <load-condition-mixin>
,
<compile-error-mixin>
,
and another <load-condition-mixin>
.
NOTE
is printed by
report-additional-condition
method of
<unbound-variable-error>
.
While loading ...
lines are printed by
report-additional-condition
method of
<load-condition-mixin>
.
While compiling ...
line is printed by
<compile-error-mixin>
.
This is called by report-error
, but you can use this procedure
separately.
Used to print additional information about a condition object
condition, to an output port out.
Some built-in conditions specializes this generic function.
See print-additional-error-heading
above for an example.
This layer provides SRFI-18 compatible simple exception mechanism.
You can override the behavior of higher-level constructs such as
with-error-handler
by using with-exception-handler
.
Note that it is a double-edged sword. You’ll get a freedom to construct your own exception handling semantics, but the Gauche system won’t save if something goes wrong. Use these primitives when you want to customize the system’s higher-level semantics or you are porting from other SRFI-18 code.
[SRFI-18] Returns the current exception handler.
[SRFI-226] Returns a fresh list of handlers in the current exception handler stack. The most recent one coming first.
[R7RS base][SRFI-34]
A procedure handler must take one argument. This procedure
sets handler to the current exception handler and calls
thunk.
(Note that this slightly differs from SRFI-18 with-exception-handler
;
we’ll explain it below.)
When an exception is raised by raise
or error
,
handler is called with the thrown condition in the
exactly same dynamic environment of raise
or error
,
except that the exception handler at the time with-exception-handler
is called is restored.
Note: SRFI-18 specifies the exception handler installed with
with-exception-handler
will be called with exactly the same
dynamic environment, including the exception handler settings.
It means if an exception is raised within the handler, it will be
caught with the same handler. The reasoning is that
with-exception-handler
is the bottom layer and kept as simple
as possible, and further semantics should be built on top of it.
Until 0.9.10 we supported SRFI-18 semantics natively, and provided R7RS semantics on top of it. However, the bare SRFI-18 semantics turned out to be error prone–users tended to assume errors from a handler would be handled by outer handler, and were perplexed when they ran into infinite recursion of handlers (which eventually caused a segfault, for the recursion eats up C stack). We decided to switch to R7RS semantics, for it is virtually always what users want.
If an exception is raised by error
, or the thrown condition
inherits <serious-condition>
, it is prohibited to return from
handler. If handler ever returns in such cases, another
error is signaled, with replacing the current exception handler to the
outer handler. So the caller of error
, or the caller of raise
with <serious-condition>
, can assume it never returns.
The behavior of those procedures can be explained in the following conceptual Scheme code.
;; Conceptual implementation of low-level exception mechanism. ;; Suppose %xh is a list of exception handlers (define (current-exception-handler) (car %xh)) (define (raise exn) (let ((prev %xh)) (dynamic-wind (lambda () (set! %xh (cdr %xh))) (lambda () (receive r ((current-exception-handler) exn) (if (uncontinuable-exception? exn) (raise (make-error "returned from uncontinuable exception")) (apply values r)))) (lambda () (set! %xh prev))))) (define (with-exception-handler handler thunk) (let ((prev %xh)) (dynamic-wind (lambda () (set! %xh (cons handler %xh))) thunk (lambda () (set! %xh prev)))))
Gauche currently has the following hierarchy of built-in condition classes. It approximately reflects SRFI-35 and SRFI-36 condition hierarchy, although they have Gauche-style class names. If there’s a corresponding SRFI condition type, the class has the SRFI name as well.
<condition> +- <compound-condition> +- <serious-condition> | +- <serious-compound-condition> ; also inherits <compound-condition> +- <message-condition> +- <error> ; also inherits <serious-condition> +- <system-error> +- <unhandled-signal-error> +- <continuation-violation> +- <read-error> +- <io-error> +- <port-error> +- <io-read-error> | +- <io-decoding-error> +- <io-write-error> | +- <io-encoding-error> +- <io-closed-error> +- <io-unit-error> +- <io-invalid-position-error>
Note that some conditions may occur simultaneously; for example,
error during reading from a file because of device failure may consist
both <system-error>
and <io-read-error>
.
In such cases, a compound condition is raised.
So you can’t just use, for instance, (is-a? obj <io-read-error>)
to check if <io-read-error>
is thrown.
See the "Condition API" section below.
Every condition class is an instance of this class.
This class defines object-apply
so that you can use
a condition class as a predicate, e.g.:
(<error> obj) ≡ (condition-has-type? obj <error>)
[SRFI-35] The root class of the condition hierarchy.
Represents a compound condition. A compound condition can be
created from one or more conditions by make-compound-condition
.
Don’t use this class directly.
A compound condition returns #t
for condition-has-type?
if any of the original conditions has the given type.
[SRFI-35]
Conditions of this class are for the situations that are too serious
to ignore or continue. Particularly, you can safely assume that
if you raise
this type of condition, it never returns.
This is an internal class to represent a compound condition
with any of its component condition is serious. Inherits both
<compound-condition>
and <serious-condition>
.
make-compound-condition
uses this class if the passed
conditions includes a serious one.
Don’t use this class directly.
[SRFI-35] This class represents a condition with a message. It has one slot.
<message-condition>
: message ¶A message.
[SRFI-35]
Indicates an error. Inherits <serious-condition>
and <message-condition>
, thus has message
slot.
Note: SRFI-35 &error
condition only inherits &serious
and not &message
, so you have to use compound condition
to attach a message to the error condition. Gauche uses multiple
inheritance here, largely because of backward compatibility.
To write a portable code, an error condition should be used
with a message condition, like this:
(condition (&message (message "Error message")) (&error))
[SRFI-35]
These are SRFI-35 compatible predicates to see if obj is
a condition of type &message
, &serious
, and &error
,
respectively.
A subclass of <error>
.
When a system call returns an error, this type of exception is
thrown. The message
slot usually contains the description
of the error (like the one from strerror(3)
).
Besides that, this class has one more instance slot:
<system-error>
: errno ¶Contains an integer value of system’s error number.
Error numbers may differ among systems. Gauche defines
constants for typical Unix error values (e.g. EACCES
, EBADF
,
etc), so it is desirable to use them instead of literal numbers.
See the description of sys-strerror
in System inquiry
for available constants.
This class doesn’t have corresponding SRFI condition type,
but important to obtain OS’s raw error code. In some cases,
this type of condition is compounded with other condition
types, like <io-read-error>
.
A subclass of <error>
. The default handler of most of
signals raises this condition. See Handling signals for
the details.
<unhandled-signal-error>
: signal ¶An integer indicating the received signal number. There are constants defined for typical signal numbers; see Signals and signal sets.
[SRFI-36]
A subclass of <error>
.
When the reader detects a lexical or syntactic error during
reading an S-expression, this type of condition is raised.
<read-error>
: port ¶A port from which the reader is reading.
(NB: SRFI-36’s &read-error
doesn’t have this slot. Portable
program shouldn’t rely on this slot).
<read-error>
: line ¶A line count (1-base) of the input where the reader raised this error. It may be -1 if the reader is reading from a port that doesn’t keep track of line count.
[SRFI-36]
A base class of I/O errors. Inherits <error>
.
[SRFI-36]
An I/O error related to a port. Inherits <io-error>
.
<port-error>
: port ¶Holds the port where the error occurred.
[SRFI-36]
An I/O error during reading from a port. Inherits <port-error>
.
[SRFI-36]
An I/O error during writing to a port. Inherits <port-error>
.
[SRFI-36]
An I/O error when read/write is attempted on a closed port.
Inherits <port-error>
.
An I/O error when the read/write is requested with a unit
that is not supported by the port (e.g. a binary I/O is requested
on a character-only port). Inherits <port-error>
.
[SRFI-226] An error thrown on violation of requirements related to continuations. A typical case is that a requested continuation prompt tag doesn’t exist in the context. See Continuation prompts, for the details.
[SRFI-226] Creates a new continuation violation condition, with prompt-tag as the continuation prompt tag that caused the violation.
[SRFI-226]
Returns #t
if obj is a <continuation-violation>
condition, #f
otherwise.
[SRFI-226]
Extract the value of prompt-tag slot
from condition, which must be a <continuation-violation>
condition.
[SRFI-35+]
Defines a new condition type. In Gauche, a condition type is
a class, whose metaclass is <condition-meta>
.
Name becomes the name of the new type, and also the variable
of that name is bound to the created condition type.
Supertype is the name of the supertype (direct superclass)
of this condition type. A condition type must inherit from
<condition>
or its descendants.
(Multiple inheritance can’t be specified by this form, and generally
should be avoided in condition type hierarchy. Instead, you
can use compound conditions, which don’t introduce multiple inheritance.)
A variable predicate is bound to a predicate procedure for this condition type.
Each field-spec
is a form of (field-name accessor-name)
,
and the condition will have fields named by field-name, and
a variable accessor-name will be bound to a procedure that
accesses the field. In Gauche, each field becomes a slot of
the created class.
Gauche extends SRFI-35 to allow predicate and/or accessor-name
to be #f
, or accessor-name
to be omitted,
if you don’t need to them to be defined.
When define-condition-type
is expanded into a class
definition, each slot gets a :init-keyword
slot option
with the keyword whose name is the same as the slot name.
[SRFI-35]
Returns #t
iff obj is a condition type. In Gauche,
it means (is-a? obj <condition-meta>)
.
[SRFI-35] A procedural version to create a new condition type.
[SRFI-35]
Creates a new condition of condition-type type, and
initializes its fields as specified by field-name
and value
pairs.
[SRFI-35]
Returns #t
iff obj is a condition. In Gauche,
it means (is-a? obj <condition>)
.
[SRFI-35]
Returns #t
iff obj belongs to a condition type type.
Because of compound conditions, this is not equivalent to is-a?
.
[SRFI-35]
Retrieves the value of field field-name of condition.
If condition is a compound condition, you can access to the
field of its original conditions; if more than one original condition
have field-name, the first one passed to make-compound-condition
has precedence.
You can use slot-ref
and/or ref
to access to the field
of conditions; compound conditions define a slot-missing
method
so that slot-ref
behaves as if the compound conditions have all the
slots of the original conditions. Using condition-ref
increases
portability, though.
[SRFI-35+]
This is a convenience procedure to retrieve a message if
condition has a type <message-condition>
,
and returns fallback otherwise. If fallback
is omitted, #f
is assumed.
Often, in a generic routine you want to intercept a raised condition and retrieve a message for logging or user feedback. Since any object can be raised in Scheme, an exception may not contain the message slot, and you need to check the type of the condition. We’ve written such code enough so that we add this procedure.
[SRFI-35]
Returns a compound condition that has all condition0 condition1
…. The returned condition’s fields are the union of all the fields
of given conditions; if any conditions have the same name of fields,
the first one takes precedence. The returned condition also has
condition-type of all the types of given conditions.
(This is not a multiple inheritance. See <compound-condition>
above.)
[SRFI-35] Condition must be a condition and have type condition-type. This procedure returns a condition of condition-type, with field values extracted from condition.
[SRFI-35]
A convenience macro to create a (possibly compound) condition.
Type-field-binding is a form of
(condition-type (field-name value-expr) …)
.
(condition (type0 (field00 value00) ...) (type1 (field10 value10) ...) ...) ≡ (make-compound-condition (make-condition type0 'field00 value00 ...) (make-condition type1 'field10 value10 ...) ...)