The MIT/GNU Scheme error system provides a uniform mechanism for the signalling of errors and other exceptional conditions. The simplest and most generally useful procedures in the error system are:
is used to signal simple errors, specifying a message and some irritant objects (see Condition Signalling). Errors are usually handled by stopping the computation and putting the user in an error REPL.
is used to signal warnings (see Condition Signalling). Warnings are usually handled by printing a message on the console and continuing the computation normally.
is used to suppress the normal handling of errors within a given dynamic
extent (see Condition Handling). Any error that occurs within the
extent is trapped, returning immediately to the caller of
More demanding applications require more powerful facilities. To give a concrete example, suppose you want floating-point division to return a very large number whenever the denominator is zero. This behavior can be implemented using the error system.
The Scheme arithmetic system can signal many different kinds of errors, including floating-point divide by zero. In our example, we would like to handle this particular condition specially, allowing the system to handle other arithmetic errors in its usual way.
The error system supports this kind of application by providing mechanisms for distinguishing different types of error conditions and for specifying where control should be transferred should a given condition arise. In this example, there is a specific object that represents the “floating-point divide by zero” condition type, and it is possible to dynamically specify an arbitrary Scheme procedure to be executed when a condition of that type is signalled. This procedure then finds the stack frame containing the call to the division operator, and returns the appropriate value from that frame.
Another useful kind of behavior is the ability to specify uniform handling for related classes of conditions. For example, it might be desirable, when opening a file for input, to gracefully handle a variety of different conditions associated with the file system. One such condition might be that the file does not exist, in which case the program will try some other action, perhaps opening a different file instead. Another related condition is that the file exists, but is read protected, so it cannot be opened for input. If these or any other related conditions occur, the program would like to skip this operation and move on to something else.
At the same time, errors unrelated to the file system should be treated in
their usual way. For example, calling
car on the argument
should signal an error. Or perhaps the name given for the file is
syntactically incorrect, a condition that probably wants to be handled
differently from the case of the file not existing.
To facilitate the handling of classes of conditions, the error system taxonomically organizes all condition types. The types are related to one another by taxonomical links, which specify that one type is a “kind of” another type. If two types are linked this way, one is considered to be a specialization of the other; or vice-versa, the second is a generalization of the first. In our example, all of the errors associated with opening an input file would be specializations of the condition type “cannot open input file”.
The taxonomy of condition types permits any condition type to have no
more than one immediate generalization. Thus, the condition types form
a forest (set of trees). While users can create new trees, the standard
taxonomy (see Condition-Type Taxonomy) is rooted at
condition-type:breakpoint; users are encouraged to add new
subtypes to these condition types rather than create new trees in the
To summarize, the error system provides facilities for the following tasks. The sections that follow will describe these facilities in more detail.
A condition may be signalled in a number of different ways. Simple
errors may be signalled, without explicitly defining a condition type,
signal-condition procedure provides the
most general signalling mechanism.
The programmer can dynamically specify handlers for particular condition
types or for classes of condition types, by means of the
bind-condition-handler procedure. Individual handlers have
complete control over the handling of a condition, and additionally may
decide not to handle a particular condition, passing it on to previously
with-restart procedure provides a means for
condition-signalling code to communicate to condition-handling code what
must be done to proceed past the condition. Handlers can examine the
restarts in effect when a condition was signalled, allowing a structured
way to continue an interrupted computation.
Each condition is represented by an explicit object. Condition objects contain information about the nature of the condition, information that describes the state of the computation from which the condition arose, and information about the ways the computation can be restarted.
Each condition has a type, represented by a condition type object. Each condition type may be a specialization of some other condition types. A group of types that share a common generalization can be handled uniformly by specifying a handler for the generalization.