###: Conditions (reduced)

by Peter McGoron

Abstract

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.

Issues

Rationale

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 subtyping instead of compound conditions?

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).

Optional features

Accessing simple conditions

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).

Specification

Required and optional features

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.

Interface

The (srfi NNN) library exports all identifiers available to the implementation.

(srfi NNN base)
procedure
(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:

  1. An implementation specific value that represents the condition type. For example, in R6RS, this should be the record type descriptor for the condition type.

  2. 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.

  3. 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.

  4. 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.

(srfi NNN base)
procedure
(condition? obj)

Returns #t if obj is a simple or compound condition, and #f otherwise.

(srfi NNN base)
procedure
(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.

(srfi NNN simple-conditions)
procedure
(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.

Standard conditions

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.

(srfi NNN base)
procedure (make-warning)
procedure (warning? obj)

A condition that signals a warning.

(srfi NNN base)
procedure (make-message-condition string)
procedure (condition-message this-condition)
procedure (message-condition? obj)

A condition that contains a message in prose that describes the condition.

(srfi NNN base)
procedure (make-irritants-condition list)
procedure (condition-irritants this-condition)
procedure (irritants-condition? obj)

A condition that contains a list of associated values. Usually, this is the arguments passed to some procedure.

(srfi NNN base)
procedure (make-error)
procedure (error? obj)

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.

(srfi NNN base)
procedure (make-assertion-violation)
procedure (assertion-violation? obj)

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.

Extensions to the R7RS

(srfi NNN r7rs)
procedure (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:

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.

Implementation

Implementations for various systems are provided in the SRFI repository. This section discusses the implementations and some implementation strategies.

Implementation strategy

If an implementation has a set of disjoint types meant to be used as conditions, then the following implementation strategy should be followed:

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.

MIT-Scheme implementation

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.

R6RS implementation

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.

Acknowledgements

Appendix 1: Other systems

This table covers the various non-R6RS implementations that were studied in the process of writing this SRFI.

ImplementationCondition system (beyond R7RS)
BiglooNo compound conditions, conditions are defined using the object system
BiwaNone (does not implement error)
Chibi SchemeError objects have a kind field
CHICKEN 6SRFI 12, expanded
CycloneNone (error objects are pairs)
GaucheSRFI 35, modified condition hierarchy, multiple inheritance
GambitNone (exceptions are records, there is no condition? supertype)
GerbilException objects are defined with multiple-inheritance object system
GoldfishNone (derived from s7)
KawaJava exceptions
LIPSJavascript exceptions
MeevaxNone
MIT-SchemeSingle inheritance condition system without compound conditions
s7None
FomentError objects have who and kind fields
STKlosSRFI 35
SKINTNone?
Stak>None

Notably, Racket uses an exception system without compound conditions, only single inheritance.

Bibliography

  1. William D. Clinger. 2007. “An essay on language design: fixing the syntactic record layer.” Retrieved from https://r6rs.org/ratification/results.html#X101 on September 21st, 2026.
  2. William D. Clinger. 2009. “SRFI 99: ERR5RS Records.”

© 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.


Editor: Arthur A. Gleckler