by Peter McGoron
A condition object system is introduced that attempts to be implementable in and interoperable with many implementation’s condition systems, including the condition system of the R6RS. The condition system includes compound conditions, but does not include subtyping of conditions. Simple conditions can be any implementation-defined value, and are also objects that can be made with the interface in this SRFI. An implementation may add other features, such as introspection and serialization.
This section is non-normative.
Conditions, which are objects that describe exceptional
situations, are implemented in many Scheme systems. In the R7RS, error objects are provided
as a way to signal errors with accompanying information, and two special
predicates (read-error? and file-error?)
are provided to check if an exception was raised by certain
procedures. These operations are designed such that they can
interoperate with the native condition system of the implementation.
The R6RS introduced a system of condition types where conditions were record types: condition types were inspectable could be subtyped. The record system of the R6RS has been criticized elsewhere [Clinger 2007, 2009], and those arguments are not particularly relevant here. The important thing is, the R6RS condition system requires the use of the criticized R6RS record type system.
The fragmentation of condition objects across implementations is an
impediment to portable code. Portable code is forced to use the
error procedure, which makes exceptional situations
difficult to describe and recover from. There is no standard
type in R7RS used to
report non-error conditions, leaving programmers to use ad-hoc
record objects.
The system described in this SRFI is an attempt to find a reduced subset of the behavior of various implementations. The goals are:
One consequence is that the SRFI does not provide for the subtyping of condition types: this is harder to make interoperate with other Scheme condition systems. Many of the benefits of subtyping can be obtained by using compound conditions, although simple conditions become more complicated.
Although the SRFI does not provide subtyping or introspection features, that does not mean that an implementation cannot provide them. Indeed, this entire SRFI can be implemented portably on top of the R6RS condition type system. Implementations are encouraged to add their own features to the condition system defined in this SRFI, which may include single inheritance, multiple inheritance, introspection, serialization, or generic functions.
Why not add subtyping instead of compound conditions? Subtyping is a more popular feature than compound conditions: see Appendix 1: Other systems. However, requiring subtyping and using it as the method of extension means that the condition hierarchy has to be spelled out explicitly. This is an issue with making a condition system work across multiple implementations, because many single-inheritance condition systems use incompatible inheritance hierarchies. There are cases where this is not possible to change, for example when a Scheme implementation is embedded in another system that offers exceptions. Example include, Kawa (Java exceptions) and LIPS (Javascript exceptions).
The R6RS has a procedure
named simple-conditions, that returns the simple conditions
of a compound condition in order. This procedure is useful when two
conditions in a compound condition have the same field accessor: this
allows the user to get both values of the field.
This feature is not required in this SRFI because it was missing from SRFI 12 and SRFI 35. Conditions of the same type are shadowed in these systems, and the implementation is free to discard them, although at least the sample implementation does not do this.
It is useful to coalese fields with the same name, because then the condition type can be represented in a multiple-inheritance object system. However, if this is not required, then an implementation should provide this interface. In particular, implementations that have native exceptions, for example Java exceptions, should provide this interface because it allows the user to access objects which may have operations that are outside of this SRFI (for instance, mutability and object identity).
The (srfi NNN) and (srfi NNN base) library
is required. The other libraries are optional but should be supplied.
If two identifiers in separate libraries have the same name, and the implementation provides both libraries, then those identifiers must be equivalent: i.e. one is a re-export of the other.
The (srfi NNN) library exports all identifiers available
to the implementation.
(make-condition-type
symbol
fields)
It is an error if fields is not either a list or a vector, and it is an error if the elements are not symbols that are all unique.
Create a new condition type with the name symbol. This syntax is generative: each invocation, even with the same symbol and field names, return a disjoint condition type.
Four values are returned:
An implementation specific value that represents the condition type. For example, in R6RS, this should be the record type descriptor for the condition type.
A constructor that take as many arguments as there are fields, and returns a simple condition with those arguments as the fields of the condition. The returned condition is immutable.
A predicate that returns true if the object is either a simple condition created with the constructor, or if the object is a compound condition that contains an object that returns true when passed to the predicate.
A vector with the same length as fields, which are accessors for this condition.
(srfi NNN base)
syntax(define-condition-type ⟨type name⟩ (⟨constructor⟩ ⟨field⟩ …) ⟨predicate⟩ (⟨fielda⟩ ⟨accessor⟩) …)
It is an error if any syntactic variable is not an identifier.
Creates a generative condition type as if by
make-condition-type.
What ⟨type name⟩ is bound to is implementation defined.
The ⟨constructor⟩/⟨predicate⟩ is bound to the
constructor/predicate returned from make-condition-type,
and the ⟨accessor⟩s are assigned to the appropriate ⟨field⟩,
matched by name.
(condition?
obj)
Returns #t if obj is a simple or compound
condition, and #f otherwise.
(condition
condition1
condition2 …)
If only one condition is supplied and it is simple, return the condition unchanged.
Otherwise, return a compound condition that contains each of the conditions in order. If one of the conditions in the argument list is compound, then the simple conditions inside of the compound condition are spliced into the list.
(simple-conditions
condition)
If condition is simple, return a list with only condition as an element.
If condition is compound, return a list that contains the simple conditions of condition in order.
The implementation may coalese condition types when creating a compound
condition: if two simple condition
objects are eqv? or are both simple immutable condition
objects of the same type that have fields that are eqv? and
are not separated by condition objects that share the same accessors,
then those two condition objects may be combined into one condition
object.
For example, consider simple condition objects c1 and c2 that both have no fields and are of the same type. Then these condition objects are immutable, and can be coalesed into one condition type inside of the compound condition, regardless of where they are.
Unless specified, these conditions may be simple or compound. As such,
the implementation dependent values that would correspond to
&message, &irritants, etc. are not provided.
An implementation that makes these conditions simple should provide these
identifiers.
In this section, it is an error if this-condition is not a condition that satisfies the predicate in the same block.
A condition that signals a warning.
(make-message-condition string)(condition-message this-condition)(message-condition? obj)A condition that contains a message in prose that describes the condition.
(make-irritants-condition list)(condition-irritants this-condition)(irritants-condition? obj)A condition that contains a list of associated values. Usually, this is the arguments passed to some procedure.
A condition that signals an error. An error is generally something that the program cannot forsee, such as an error in attempting to access the filesystem, or an error due to malformed user input.
An assertion violation is raised when a procedure is called incorrectly. For example, when a procedure is passed the wrong number of arguments, or if a procedure is given a value of the wrong type.
Note: A Scheme program should* never depend on assertion violations being raised. Locations where assertion violations occur are generally those locations where the behavior “is an error” in the R7RS. They are places where extensions may occur, either in newer standards or in implementations.
*: Used in the sense of the authors opinion, not an RFC 2119 requirement word.
(error-object? obj)(read-error? obj)(file-error? obj)(error-object-message error-object)(error-object-irritants error-object)These procedures are extended such that:
error-object? if it is a compound condition
object that has a system error object inside of it.read-error? if it is a compound condition
object with a system read-error object inside of it.file-error? if it is a compound condition
object with a system file-error object inside of it.error-object-message
and error-object-irritants
works on compound conditions with error objects in them.
An implementation may make an error object a compound
condition that is made up of an error? condition,
message-condition, and irritants-condition.
Note: Error objects, read errors, and file errors are not required to be compound condition objects. An implementation can continue to use its old representations.
Implementations are encouraged to replace the versions of these
procedures in (scheme base) with the one defined in this SRFI. The
ones defined in this SRFI are backwards-compatible with the versions
described in the R7RS.
Implementations for various systems are provided in the SRFI repository. This section discusses the implementations and some implementation strategies.
If an implementation has a set of disjoint types meant to be used as conditions, then the following implementation strategy should be followed:
#t when applied to a
compound condition with an object of that type in it.This may entail a change to the representation of error objects in the implementation, and any exported predicates/accessors will have to be changed. However, code that was previously written for the implementation’s error object system will be compatible with this SRFI’s system, and allow for complete interoperation with condition types defined using the interface in this SRFI.
An implementation for MIT-Scheme is provided as a patch to the
runtime and a library file implementing the identifiers of this SRFI.
Compound conditions are instances of a MIT-Scheme condition
type that has single field. The modifications to the runtime mean
that procedures constructed using condition-accessor
and condition-predicate will automatically work with
compound conditions.
MIT-Scheme is an instructive example of how one could extend the conditions in this SRFI. MIT-Scheme conditions have a continuation and restarter field. Compound conditions take the continuation and restarter field of the first condition passed to the constructor.
This SRFI is a subset of the behavior of the R6RS
system.
Condition types defined by this SRFI are inheritable
by R6RS’s
define-condition-type and inspectable using
the R6RS’s
interfaces, and conditions defined by the R6RS can be used in the procedures
defined in this SRFI.
This table covers the various non-R6RS implementations that were studied in the process of writing this SRFI.
| Implementation | Condition system (beyond R7RS) |
|---|---|
| Bigloo | No compound conditions, conditions are defined using the object system |
| Biwa | None (does not implement error) |
| Chibi Scheme | Error objects have a kind field |
| CHICKEN 6 | SRFI 12, expanded |
| Cyclone | None (error objects are pairs) |
| Gauche | SRFI 35, modified condition hierarchy, multiple inheritance |
| Gambit | None (exceptions are records, there is no condition? supertype) |
| Gerbil | Exception objects are defined with multiple-inheritance object system |
| Goldfish | None (derived from s7) |
| Kawa | Java exceptions |
| LIPS | Javascript exceptions |
| Meevax | None |
| MIT-Scheme | Single inheritance condition system without compound conditions |
| s7 | None |
| Foment | Error objects have who and kind fields |
| STKlos | SRFI 35 |
| SKINT | None? |
| Stak> | None |
Notably, Racket uses an exception system without compound conditions, only single inheritance.
© 2026 Peter McGoron.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.