MIT Scheme Reference: Error System

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

# 16. Error System

The MIT 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:

`error`
  is used to signal simple errors, specifying a message and some irritant objects (see section 16.1 Condition Signalling). Errors are usually handled by stopping the computation and putting the user in an error REPL.

`warn`
  is used to signal warnings (see section 16.1 Condition Signalling). Warnings are usually handled by printing a message on the console and continuing the computation normally.

`ignore-errors`
  is used to suppress the normal handling of errors within a given dynamic extent (see section 16.3 Condition Handling). Any error that occurs within the extent is trapped, returning immediately to the caller of `ignore-errors`.

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 `3` 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 section 16.7 Condition-Type Taxonomy) is rooted at `condition-type:serious-condition`, `condition-type:warning`, `condition-type:simple-condition`, and `condition-type:breakpoint`; users are encouraged to add new subtypes to these condition types rather than create new trees in the forest.

To summarize, the error system provides facilities for the following tasks. The sections that follow will describe these facilities in more detail.

Signalling a condition
  A condition may be signalled in a number of different ways. Simple errors may be signalled, without explicitly defining a condition type, using `error`. The `signal-condition` procedure provides the most general signalling mechanism.

Handling a condition
  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 bound handlers.

Restarting from a handler
  The `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.

Packaging condition state
  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.

Classification of conditions
  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.

> 16.1 Condition Signalling |  |
> 16.2 Error Messages |  |
> 16.3 Condition Handling |  |
> 16.4 Restarts |  |
> 16.5 Condition Instances |  |
> 16.6 Condition Types |  |
> 16.7 Condition-Type Taxonomy |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.1 Condition Signalling

Once a condition instance has been created using `make-condition` (or any condition constructor), it can be signalled. The act of signalling a condition is separated from the act of creating the condition to allow more flexibility in how conditions are handled. For example, a condition instance could be returned as the value of a procedure, indicating that something unusual has happened, to allow the caller to clean up some state. The caller could then signal the condition once it is ready.

A more important reason for having a separate condition-signalling mechanism is that it allows resignalling. When a signalled condition has been caught by a particular handler, and the handler decides that it doesn't want to process that particular condition, it can signal the condition again. This is one way to allow other handlers to get a chance to see the condition.

procedure: error reason argument...
  This is the simplest and most common way to signal a condition that requires intervention before a computation can proceed (when intervention is not required, `warn` is more appropriate). `error` signals a condition (using `signal-condition`), and if no handler for that condition alters the flow of control (by invoking a restart, for example) it calls the procedure `standard-error-handler`, which normally prints an error message and stops the computation, entering an error REPL. Under normal circumstances `error` will not return a value (although an interactive debugger can be used to force this to occur).

  Precisely what condition is signalled depends on the first argument to `error`. If reason is a condition, then that condition is signalled and the arguments are ignored. If reason is a condition type, then a new instance of this type is generated and signalled; the arguments are used to generate the values of the fields for this condition type (they are passed as the field-plist argument to `make-condition`). In the most common case, however, reason is neither a condition nor a condition type, but rather a string or symbol. In this case a condition of type `condition-type:simple-error` is created with the message field containing the reason and the irritants field containing the arguments.

procedure: warn reason argument...
  When a condition is not severe enough to warrant intervention, it is appropriate to signal the condition with `warn` rather than `error`. As with `error`, `warn` first calls `signal-condition`; the condition that is signalled is chosen exactly as in `error` except that a condition of type `condition-type:simple-warning` is signalled if reason is neither a condition nor a condition type. If the condition is not handled, `warn` calls the procedure `standard-warning-handler`, which normally prints a warning message and continues the computation by returning from `warn`.

  `warn` establishes a restart named `muffle-warning` before calling `signal-condition`. This allows a signal handler to prevent the generation of the warning message by calling `muffle-warning`. The value of a call to `warn` is unspecified.

procedure: signal-condition condition
  This is the fundamental operation for signalling a condition. The precise operation of `signal-condition` depends on the condition type of which condition is an instance, the condition types set by `break-on-signals`, and the handlers established by `bind-condition-handler` and `bind-default-condition-handler`.

  If the condition is an instance of a type that is a specialization of any of the types specified by `break-on-signals`, then a breakpoint REPL is initiated. Otherwise (or when that REPL returns), the handlers established by `bind-condition-handler` are checked, most recent first. Each applicable handler is invoked, and the search for a handler continues if the handler returns normally. If all applicable handlers return, then the applicable handlers established by `bind-default-condition-handler` are checked, again most recent first. Finally, if no handlers apply (or all return in a normal manner), `signal-condition` returns an unspecified value.

  Note: unlike many other systems, the MIT Scheme runtime library does not establish handlers of any kind. (However, the Edwin text editor uses condition handlers extensively.) Thus, calls to `signal-condition` will return to the caller unless there are user supplied condition handlers, as the following example shows:

      (signal-condition
       (make-condition
        condition-type:error
        (call-with-current-continuation (lambda (x) x))
        '()    ; no restarts
        '()))  ; no fields
      =>  unspecified

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.2 Error Messages

By convention, error messages (and in general, the reports generated by `write-condition-report`) should consist of one or more complete sentences. The usual rules for sentences should be followed: the first word of the sentence should be capitalized, and the sentence should be terminated by a period. The message should not contain extraneous whitespace such as line breaks or indentation.

The error system provides a simple formatting language that allows the programmer to have some control over the printing of error messages. This formatting language will probably be redesigned in a future release.

Error messages typically consist of a string describing the error, followed by some irritant objects. The string is printed using `display`, and the irritants are printed using `write`, typically with a space between each irritant. To allow simple formatting, we introduce a noise object, printed using `display`. The irritant list may contain ordinary objects interspersed with noise objects. Each noise object is printed using `display`, with no extra whitespace, while each normal object is printed using `write`, prefixed by a single space character.

Here is an example:

    (define (error-within-procedure message irritant procedure)
      (error message
             irritant
             (error-irritant/noise "within procedure")
             procedure
             (error-irritant/noise ".")))

This would format as follows:

    (error-within-procedure "Bad widget" 'widget-32 'invert-widget) error-->

    Bad widget widget-32 within procedure invert-widget.

Here are the operations supporting error messages:

procedure: format-error-message message irritants port
  Message is typically a string (although this is not required), irritants a list of irritant objects, and port an output port. Formats message and irritants to port in the standard way. Note that, during the formatting process, the depth and breadth to which lists are printed are each limited to small numbers, to guarantee that the output from each irritant is not arbitrarily large.

procedure: error-irritant/noise value
  Creates and returns a noise object whose value is value.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.3 Condition Handling

The occurrence of a condition is signalled using `signal-condition`. `signal-condition` attempts to locate and invoke a condition handler that is prepared to deal with the type of condition that has occurred. A condition handler is a procedure of one parameter, the condition that is being signalled. A procedure is installed as a condition handler by calling `bind-condition-handler` (to establish a handler that is in effect only while a particular thunk is executing) or `bind-default-condition-handler` (to establish a handler that is in effect permanently). As implied by the name, handlers created by `bind-default-condition-handler` are invoked only after all other applicable handlers have been invoked.

A handler may process a signal in any way it deems appropriate, but the common patterns are:

Ignore the condition.
  By returning from the handler in the usual manner.

Handle the condition.
  By doing some processing and then invoking a restart (or, less preferably, a continuation) that was established at some point prior to the call to `signal-condition`.

Resignal a condition.
  By doing some processing and calling `signal-condition` with either the same condition or a newly created one. In order to support this, `signal-condition` runs handler in such a way that a subsequent call to `signal-condition` sees only the handlers that were established prior to this one.

As an aid to debugging condition handlers, Scheme maintains a set of condition types that will cause an interactive breakpoint to occur prior to normal condition signalling. That is, `signal-condition` creates a new REPL prior to its normal operation when its argument is a condition that is a specialization of any of these types. The procedure `break-on-signals` establishes this set of condition types.

procedure: ignore-errors thunk
  Executes thunk with a condition handler that intercepts the signalling of any specialization of `condition-type:error` (including those produced by calls to `error`) and immediately terminates the execution of thunk and returns from the call to `ignore-errors` with the signalled condition as its value. If thunk returns normally, its value is returned from `ignore-errors`.

  Notice that `ignore-errors` does not "turn off signalling" or condition handling. Condition handling takes place in the normal manner but conditions specialized from `condition-type:error` are trapped rather than propogated as they would be by default.

procedure: bind-condition-handler condition-types handler thunk
  Invokes thunk after adding handler as a condition handler for the conditions specified by condition-types. Condition-types must be a list of condition types; signalling a condition whose type is a specialization of any of these types will cause the handler to be invoked. See `signal-condition` for a description of the mechanism used to invoke handlers.

  By special extension, if condition-types is the empty list then the handler is called for all conditions.

procedure: bind-default-condition-handler condition-types handler
  Installs handler as a (permanent) condition handler for the conditions specified by condition-types. Condition-types must be a list of condition types; signalling a condition whose type is a specialization of any of these types will cause the handler to be invoked. See `signal-condition` for a description of the mechanism used to invoke handlers.

  By special extension, if condition-types is the empty list then the handler is called for all conditions.

procedure: break-on-signals condition-types
  Arranges for `signal-condition` to create an interactive REPL before it signals a condition that is a specialization of any of the types in the list of condition-types. This can be extremely helpful when trying to debug code that uses custom condition handlers. In order to create a REPL when any condition type is signalled it is best to actually put a breakpoint on entry to `signal-condition`.

procedure: standard-error-handler condition
  Called internally by `error` after it calls `signal-condition`. Normally creates creates a new REPL with the prompt `"error>"` (but see `standard-error-hook`). In order to simulate the effect of calling `error`, code may call `signal-condition` directly and then call `standard-error-handler` if `signal-condition` returns.

variable: standard-error-hook
  This variable controls the behavior of the procedure `standard-error-handler`, and hence `error`. It is intended to be bound with `fluid-let` and is normally `#f`. It may be changed to a procedure of one argument and will then be invoked (with `standard-error-hook` rebound to `#f`) by `standard-error-handler` just prior to starting the error REPL. It is passed one argument, the condition being signalled.

procedure: standard-warning-handler condition
  This is the procedure called internally by `warn` after it calls `signal-condition`. The normal behavior of `standard-warning-handler` is to print a message (but see `standard-warning-hook`). More precisely, the message is printed to the port returned by `notification-output-port`. The message is formed by first printing the string `"Warning: "` to this port, and then calling `write-condition-report` on condition and the port.

  In order to simulate the effect of calling `warn`, code may call `signal-condition` directly and then call `standard-warning-handler` if `signal-condition` returns. (This is not sufficient to implement the `muffle-warning` protocol, however. For that purpose an explicit restart must be provided.)

variable: standard-warning-hook
  This variable controls the behavior of the procedure `standard-warning-handler`, and hence `warn`. It is intended to be bound with `fluid-let` and is normally `#f`. It may be changed to a procedure of one argument and will then be invoked (with `standard-warning-hook` rebound to `#f`) by `standard-warning-handler` in lieu of writing the warning message. It is passed one argument, the condition being signalled.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.4 Restarts

The Scheme error system provides a mechanism, known as restarts, that helps coordinate condition-signalling code with condition-handling code. A module of code that detects and signals conditions can provide procedures (using `with-simple-restart` or `with-restart`) to be invoked by handlers that wish to continue, abort, or restart the computation. These procedures, called restart effectors, are encapsulated in restart objects.

When a condition object is created, it contains a set of restart objects, each of which contains a restart effector. Condition handlers can inspect the condition they are handling (using `find-restart` to find restarts by name, or `condition/restarts` to see the entire set), and they can invoke the associated effectors (using `invoke-restart` or `invoke-restart-interactively`). Effectors can take arguments, and these may be computed directly by the condition-handling code or by gathering them interactively from the user.

The names of restarts can be chosen arbitrarily, but the choice of name is significant. These names are used to coordinate between the signalling code (which supplies names for restarts) and the handling code (which typically chooses a restart effector by the name of its restart). Thus, the names specify the restart protocol implemented by the signalling code and invoked by the handling code. The protocol indicates the number of arguments required by the effector code as well as the semantics of the arguments.

Scheme provides a conventional set of names (hence, protocols) for common use. By choosing the names of restarts from this set, signalling code can indicate that it is able to perform a small set of fairly common actions (`abort`, `continue`, `muffle-warning`, `retry`, `store-value`, `use-value`). In turn, simple condition-handling code can look for the kind of action it wishes to perform and simply invoke it by name. All of Scheme's conventional names are symbols, although in general restart names are not restricted to any particular data type. In addition, the object `#f` is reserved to indicate the "not for automated use" protocol: these restarts should be activated only under human control.

Restarts themselves are first-class objects. They encapsulate their name, a procedure (known as the effector) to be executed if they are invoked, and a thunk (known as the reporter) that can be invoked to display a description of the restart (used, for example, by the interactive debugger). Invoking a restart is an indication that a handler has chosen to accept control for a condition; as a consequence, the effector of the restart should not return, since this would indicate that the handler declined to handle the condition. Thus, the effector should call a continuation captured before the condition-signalling process began. The most common pattern of usage by signalling code is encapsulated in `with-simple-restart`.

Within this chapter, a parameter named restarts will accept any of the following values:

- A list of restart objects.

- A condition. The procedure `condition/restarts` is called on the condition, and the resulting list of restarts is used in place of the condition.

- The symbol `bound-restarts`. The procedure `bound-restarts` is called (with no arguments), and the resulting list of restarts is used in place of the symbol.

- If the restarts parameter is optional and is not supplied, it is equivalent to having specified the symbol `bound-restarts`.

> 16.4.1 Establishing Restart Code |  |
> 16.4.2 Invoking Standard Restart Code |  |
> 16.4.3 Finding and Invoking General Restart Code |  |
> 16.4.4 The Named Restart Abstraction |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.4.1 Establishing Restart Code

procedure: with-simple-restart name reporter thunk
  Invokes thunk in a dynamic environment created by adding a restart named name to the existing named restarts. Reporter may be used during the execution of thunk to produce a description of the newly created restart; it must either be a procedure of one argument (a port) or a string. By convention, the description generated by reporter should be a short complete sentence, with first word capitalized and terminated by a period. The sentence should fit on one line with a little room to spare (see the examples below); usually this means that the sentence should be 70 characters or less in length.

  If the restart created by `with-simple-restart` is invoked it simply aborts the computation in progress by returning an unspecified value from the call to `with-simple-restart`. Otherwise `with-simple-restart` returns the value computed by thunk.

    (with-simple-restart 'george "This restart is named george."
      (lambda () 3)) => 3

    (with-simple-restart 'george "This restart is named george."
      (lambda ()
        (invoke-restart (find-restart 'george)))) => unspecific

    (with-simple-restart 'george "This restart is named george."
      (lambda () (car 3)))
    ;The object 3, passed as the first argument to car,
    ; is not the correct type.
    ;To continue, call RESTART with an option number:
    ; (RESTART 3) => Specify an argument to use in its place.
    ; (RESTART 2) => This restart is named george.
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: with-restart name reporter effector interactor thunk
  Invokes thunk in a dynamic environment created by adding a restart named name to the existing named restarts. Reporter may be used during the execution of thunk to produce a description of the newly created restart; it must either be a procedure of one argument (a port) or a string. Effector is a procedure which will be called when the restart is invoked by `invoke-restart`. Interactor specifies the arguments that are to be passed to effector when it is invoked interactively; it may be either a procedure of no arguments, or `#f`. If interactor is `#f`, this restart is not meant to be invoked interactively.

  The value returned by `with-restart` is the value returned by thunk. Should the restart be invoked by a condition handler, however, the effector will not return back to the handler that invoked it. Instead, the effector should call a continuation created before the condition-signalling process began, and `with-restart` will therefore not return in the normal manner.

    (define (by-george! thunk)
      ; This code handles conditions that arise while executing thunk
      ; by invoking the GEORGE restart, passing 1 and 2 to the restart's
      ; effector code.
      (bind-condition-handler '() ; All conditions
       (lambda (condition)
         (invoke-restart (find-restart 'george) 1 2))
       thunk))

    (define (can-george! thunk)
      ; This code provides a way of handling errors: the GEORGE restart.
      ; In order to GEORGE you must supply two values.
      (lambda ()
        (call-with-current-continuation
         (lambda (kappa)
           (with-restart
            'george                         ; Name
            "This restart is named george." ; Reporter
            (lambda (a b)                   ; Effector
              (kappa (list 'george a b)))
            values                          ; Interactor
            thunk)))))                      ; Thunk

    (by-george! (can-george! (lambda () -3))        => -3
    (by-george! (can-george! (lambda () (car 'x)))) => (george 1 2)

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.4.2 Invoking Standard Restart Code

Scheme supports six standard protocols for restarting from a condition, each encapsulated using a named restart (for use by condition-signalling code) and a simple procedure (for use by condition-handling code). Unless otherwise specified, if one of these procedures is unable to find its corresponding restart, it returns immediately with an unspecified value.

Each of these procedures accepts an optional argument restarts, which is described above in 16.4 Restarts.

procedure: abort [restarts]
  Abort the computation, using the restart named `abort`. The corresponding effector takes no arguments and abandons the current line of computation. This is the restart provided by Scheme's REPL.

  If there is no restart named `abort`, this procedure signals an error of type `condition-type:no-such-restart`.

procedure: continue [restarts]
  Continue the current computation, using the restart named `continue`. The corresponding effector takes no arguments and continues the computation beyond the point at which the condition was signalled.

procedure: muffle-warning [restarts]
  Continue the current computation, using the restart named `muffle-warning`. The corresponding effector takes no arguments and continues the computation beyond the point at which any warning message resulting from the condition would be presented to the user. The procedure `warn` establishes a `muffle-warning` restart for this purpose.

  If there is no restart named `muffle-warning`, this procedure signals an error of type `condition-type:no-such-restart`.

procedure: retry [restarts]
  Retry the current computation, using the restart named `retry`. The corresponding effector takes no arguments and simply retries the same computation that triggered the condition. The condition may reoccur, of course, if the root cause has not been eliminated. The code that signals a "file does not exist" error can be expected to supply a `retry` restart. The restart would be invoked after first creating the missing file, since the computation is then likely to succeed if it is simply retried.

procedure: store-value new-value [restarts]
  Retry the current computation, using the restart named `store-value`, after first storing new-value. The corresponding effector takes one argument, new-value, and stores it away in a restart-dependent location, then retries the same computation that triggered the condition. The condition may reoccur, of course, if the root cause has not been eliminated. The code that signals an "unassigned variable" error can be expected to supply a `store-value` restart; this would store the value in the variable and continue the computation.

procedure: use-value new-value [restarts]
  Retry the current computation, using the restart named `use-value`, but substituting new-value for a value that previously caused a failure. The corresponding effector takes one argument, new-value, and retries the same computation that triggered the condition with the new value substituted for the failing value. The condition may reoccur, of course, if the new value also induces the condition.

  The code that signals an "unassigned variable" error can be expected to supply a `use-value` restart; this would simply continue the computation with new-value instead of the value of the variable. Contrast this with the `retry` and `store-value` restarts. If the `retry` restart is used it will fail because the variable still has no value. The `store-value` restart could be used, but it would alter the value of the variable, so that future references to the variable would not be detected.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.4.3 Finding and Invoking General Restart Code

Restarts are a general mechanism for establishing a protocol between condition-signalling and condition-handling code. The Scheme error system provides "packaging" for a number of common protocols. It also provides lower-level hooks that are intended for implementing customized protocols. The mechanism used by signalling code (`with-restart` and `with-simple-restart`) is used for both purposes.

Four additional operations are provided for the use of condition-handling code. Two operations (`bound-restarts` and `find-restart`) allow condition-handling code to locate active restarts. The other two operations (`invoke-restart` and `invoke-restart-interactively`) allow restart effectors to be invoked once the restart object has been located.

In addition, there is a data abstraction that provides access to the information encapsulated in restart objects.

procedure: bound-restarts
  Returns a list of all currently active restart objects, most recently installed first. `bound-restarts` should be used with caution by condition-handling code, since it reveals all restarts that are active at the time it is called, rather than at the time the condition was signalled. It is useful, however, for collecting the list of restarts for inclusion in newly generated condition objects or for inspecting the current state of the system.

procedure: find-restart name [restarts]
  Returns the first restart object named name in the list of restarts (permissible values for restarts are described above in 16.4 Restarts). When used in a condition handler, `find-restart` is usually passed the name of a particular restart and the condition object that has been signalled. In this way the handler finds only restarts that were available when the condition was created (usually the same as when it was signalled). If restarts is omitted, the currently active restarts would be used, and these often include restarts added after the condition ocurred.

procedure: invoke-restart restart argument...
  Calls the restart effector encapsulated in restart, passing the specified arguments to it. `invoke-restart` is intended for use by condition-handling code that understands the protocol implemented by restart, and can therefore calculate and pass an appropriate set of arguments.

  If a condition handler needs to interact with a user to gather the arguments for an effector (e.g. if it does not understand the protocol implemented by restart) `invoke-restart-interactively` should be used instead of `invoke-restart`.

procedure: invoke-restart-interactively restart
  First calls the interactor encapsulated in restart to interactively gather the arguments needed for restart's effector. It then calls the effector, passing these arguments to it.

  `invoke-restart-interactively` is intended for calling interactive restarts (those for which `restart/interactor` is not `#f`). For convenience, `invoke-restart-interactively` will call the restart's effector with no arguments if the restart has no interactor; this behavior may change in the future.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.4.4 The Named Restart Abstraction

A restart object is very simple, since it encapsulates only a name, effector, interactor, and description.

procedure: restart? object
  Returns `#f` if and only if object is not a restart.

procedure: restart/name restart
  Returns the name of restart. While the Scheme error system uses only symbols and the object `#f` for its predefined names, programs may use arbitrary objects (name equivalence is tested using `eq?`).

procedure: restart/effector restart
  Returns the effector encapsulated in restart. Normally this procedure is not used since `invoke-restart` and `invoke-restart-interactively` capture the most common invocation patterns.

procedure: restart/interactor restart
  Returns the interactor encapsulated in restart. This is either a procedure of no arguments or the object `#f`. Normally this procedure is not used since `invoke-restart-interactively` captures the most common usage. Thus `restart/interactor` is most useful as a predicate to determine if restart is intended to be invoked interactively.

procedure: write-restart-report restart port
  Writes a description of restart to port. This works by either displaying (if it is a string) or calling (if it is a procedure) the reporter that was supplied when the restart was created.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.5 Condition Instances

A condition, in addition to the information associated with its type, usually contains other information that is not shared with other conditions of the same type. For example, the condition type associated with "unbound variable" errors does not specify the name of the variable that was unbound. The additional information is captured in a condition object, also called a condition instance.

In addition to information that is specific to a given type of condition (such as the variable name for "unbound variable" conditions), every condition instance also contains a continuation that encapsulates the state of the computation in which the condition occurred. This continuation is used for analyzing the computation to learn more about the context in which the condition occurred. It is not intended to provide a mechanism for continuing the computation; that mechanism is provided by restarts.

> 16.5.1 Generating Operations on Conditions |  |
> 16.5.2 Condition Abstraction |  |
> 16.5.3 Simple Operations on Condition Instances |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.5.1 Generating Operations on Conditions

Scheme provides four procedures that take a condition type as input and produce operations on the corresponding condition object. These are reminiscent of the operations on record types that produce record operators (see section 10.4 Records). Given a condition type it is possible to generate: a constructor for instances of the type (using `condition-constructor`); an accessor to extract the contents of a field in instances of the type (using `condition-accessor`); a predicate to test for instances of the type (using `condition-predicate`); and a procedure to create and signal an instance of the type (using `condition-signaller`).

Notice that the creation of a condition object is distinct from signalling an occurrence of the condition. Condition objects are first-class; they may be created and never signalled, or they may be signalled more than once. Further notice that there are no procedures for modifying conditions; once created, a condition cannot be altered.

procedure: condition-constructor condition-type field-names
  Returns a constructor procedure that takes as arguments values for the fields specified in field-names and creates a condition of type condition-type. Field-names must be a list of symbols that is a subset of the field-names in condition-type. The constructor procedure returned by `condition-constructor` has signature

      (lambda (continuation restarts . field-values) ...)

  where the field-names correspond to the field-values. The constructor argument restarts is described in 16.4 Restarts. Conditions created by the constructor procedure have `#f` for the values of all fields other than those specified by field-names.

  For example, the following procedure `make-simple-warning` constructs a condition of type `condition-type:simple-warning` given a continuation (where the condition occurred), a description of the restarts to be made available, a warning message, and a list of irritants that caused the warning:

      (define make-simple-warning
        (condition-constructor condition-type:simple-warning
                               '(message irritants)))

procedure: condition-accessor condition-type field-name
  Returns a procedure that takes as input a condition object of type condition-type and extracts the contents of the specified field-name. `condition-accessor` signals `error:bad-range-argument` if the field-name isn't one of the named fields of condition-type; the returned procedure will signal `error:wrong-type-argument` if passed an object other than a condition of type condition-type or one of its specializations.

  If it is known in advance that a particular field of a condition will be accessed repeatedly it is worth constructing an accessor for the field using `condition-accessor` rather than using the (possibly more convenient, but slower) `access-condition` procedure.

procedure: condition-predicate condition-type
  Returns a predicate procedure for testing whether an object is a condition of type condition-type or one of its specializations (there is no predefined way to test for a condition of a given type but not a specialization of that type).

procedure: condition-signaller condition-type field-names default-handler
  Returns a signalling procedure with parameters field-names. When the signalling procedure is called it creates and signals a condition of type condition-type. If the condition isn't handled (i.e. if no handler is invoked that causes an escape from the current continuation) the signalling procedure reduces to a call to default-handler with the condition as its argument.

  There are several standard procedures that are conventionally used for default-handler. If condition-type is a specialization of `condition-type:error`, default-handler should be the procedure
  `standard-error-handler`. If condition-type is a specialization of `condition-type:warning`, default-handler should be the procedure `standard-warning-handler`. If condition-type is a specialization of `condition-type:breakpoint`, default-handler should be the procedure `standard-breakpoint-handler`.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.5.2 Condition Abstraction

The condition data type is abstracted through a predicate `condition?` and a set of accessor procedures.

procedure: condition? object
  Returns `#f` if and only if object is not a condition.

procedure: condition/type condition
  Returns the condition type of which condition is an instance.

procedure: condition/error? condition
  Returns `#t` if the condition is an instance of condition type `condition-type:error` or a specialization of it, `#f` otherwise.

procedure: condition/restarts condition
  Returns the list of restarts specified when condition was created.

procedure: condition/continuation condition
  Returns the continuation specified when condition was created. This is provided for inspecting the state of the system when the condition occurred, not for continuing or restarting the computation.

procedure: write-condition-report condition port
  Writes a description of condition to port, using the reporter function from the condition type associated with condition. See also `condition/report-string`.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 16.5.3 Simple Operations on Condition Instances

The simple procedures described in this section are built on top of the more detailed abstraction of condition objects described above. While these procedures are sometimes easier to use, they are often less efficient.

procedure: make-condition condition-type continuation restarts field-plist
  Create a new condition object as an instance of condition-type, associated with continuation. The continuation is provided for inspection purposes only, not for restarting the computation. The restarts argument is described in 16.4 Restarts. The field-plist is an alternating list of field names and values for those fields, where the field names are those that would be returned by `(condition-type/field-names condition-type)`. It is used to provide values for fields in the condition object; fields with no value specified are set to `#f`. Once a condition object has been created there is no way to alter the values of these fields.

procedure: access-condition condition field-name
  Returns the value stored in the field field-name within condition. Field-name must be one of the names returned by `(condition-type/field-names (condition/type condition))`. `access-condition` looks up the field-name at runtime, so it is more efficient to use `condition-accessor` to create an access function if the same field is to be extracted from several instances of the same condition type.

procedure: condition/report-string condition
  Returns a string containing a report of the condition. This is generated by calling `write-condition-report` on condition and a string output port, and returning the output collected by the port as a string.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.6 Condition Types

Each condition has a condition type object associated with it. These objects are used as a means of focusing on related classes of conditions, first by concentrating all of the information about a specific class of condition in a single place, and second by specifying an inheritance relationship between types. This inheritance relationship forms the taxonomic structure of the condition hierarchy (see section 16.7 Condition-Type Taxonomy).

The following procedures consititute the abstraction for condition types.

procedure: make-condition-type name generalization field-names reporter
  Creates and returns a (new) condition type that is a specialization of generalization (if it is a condition type) or is the root of a new tree of condition types (if generalization is `#f`). For debugging purposes, the condition type has a name, and instances of this type contain storage for the fields specified by field-names (a list of symbols) in addition to the fields common to all conditions (type, continuation and restarts).

  Reporter is used to produce a description of a particular condition of this type. It may be a string describing the condition, a procedure of arity two (the first argument will be a condition of this type and the second a port) that will `write` the message to the given port, or `#f` to specify that the reporter should be taken from the condition type generalization (or produce an "undocumented condition of type ..." message if generalization is `#f`). The conventions used to form descriptions are spelled out in 16.2 Error Messages.

procedure: condition-type/error? condition-type
  Returns `#t` if the condition-type is `condition-type:error` or a specialization of it, `#f` otherwise.

procedure: condition-type/field-names condition-type
  Returns a list of all of the field names for a condition of type condition-type. This is the set union of the fields specified when this condition-type was created with the `condition-type/field-names` of the generalization of this condition-type.

procedure: condition-type/generalizations condition-type
  Returns a list of all of the generalizations of condition-type. Notice that every condition type is considered a generalization of itself.

procedure: condition-type? object
  Returns `#f` if and only if object is not a condition type.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 16.7 Condition-Type Taxonomy

The MIT Scheme error system provides a rich set of predefined condition types. These are organized into a forest through taxonomic links providing the relationships for "specializes" and "generalizes". The chart appearing below shows these relationships by indenting all the specializations of a given type relative to the type. Note that the variables that are bound to these condition types are prefixed by ``condition-type:`'; for example, the type appearing in the following table as ``simple-error`' is stored in the variable `condition-type:simple-error`. Users are encouraged to add new condition types by creating specializations of existing ones.

Following the chart are detailed descriptions of the predefined condition types. Some of these types are marked as abstract types. Abstract types are not intended to be used directly as the type of a condition; they are to be used as generalizations of other types, and for binding condition handlers. Types that are not marked as abstract are concrete; they are intended to be explicitly used as a condition's type.

    serious-condition
        error
            simple-error
            illegal-datum
                wrong-type-datum
                    wrong-type-argument
                    wrong-number-of-arguments
                datum-out-of-range
                    bad-range-argument
                inapplicable-object
            file-error
                file-operation-error
                derived-file-error
            port-error
                derived-port-error
            variable-error
                unbound-variable
                unassigned-variable
            arithmetic-error
                divide-by-zero
                floating-point-overflow
                floating-point-underflow
            control-error
                no-such-restart
            not-loading
            primitive-procedure-error
                system-call-error
    warning
        simple-warning
    simple-condition
    breakpoint

condition type: condition-type:serious-condition
  This is an abstract type. All serious conditions that require some form of intervention should inherit from this type. In particular, all errors inherit from this type.

condition type: condition-type:error
  This is an abstract type. All errors should inherit from this type.

condition type: condition-type:simple-error message irritants
  This is the condition generated by the `error` procedure when its first argument is not a condition or condition type. The fields message and irritants are taken directly from the arguments to `error`; message contains an object (usually a string) and irritants contains a list of objects. The reporter for this type uses `format-error-message` to generate its output from message and irritants.

condition type: condition-type:illegal-datum datum
  This is an abstract type. This type indicates the class of errors in which a program discovers an object that lacks specific required properties. Most commonly, the object is of the wrong type or is outside a specific range. The datum field contains the offending object.

condition type: condition-type:wrong-type-datum datum type
  This type indicates the class of errors in which a program discovers an object that is of the wrong type. The type field contains a string describing the type that was expected, and the datum field contains the object that is of the wrong type.

    (error:wrong-type-datum 3.4 "integer")  error-->
    ;The object 3.4 is not an integer.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:wrong-type-datum datum type
  This procedure signals a condition of type `condition-type:wrong-type-datum`. The datum and type fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:wrong-type-argument datum type operator operand
  This type indicates that a procedure was passed an argument of the wrong type. The operator field contains the procedure (or a symbol naming the procedure), the operand field indicates the argument position that was involved (this field contains either a symbol, a non-negative integer, or `#f`), the type field contains a string describing the type that was expected, and the datum field contains the offending argument.

    (+ 'a 3)                                error-->
    ;The object a, passed as the first argument to integer-add,
    ; is not the correct type.
    ;To continue, call RESTART with an option number:
    ; (RESTART 2) => Specify an argument to use in its place.
    ; (RESTART 1) => Return to read-eval-print level 1.

    (list-copy 3)
    ;The object 3, passed as an argument to list-copy, is not a list.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:wrong-type-argument datum type operator
  This procedure signals a condition of type `condition-type:wrong-type-argument`. The datum, type and operator fields of the condition are filled in from the corresponding arguments to the procedure; the operand field of the condition is set to `#f`.

condition type: condition-type:wrong-number-of-arguments datum type operands
  This type indicates that a procedure was called with the wrong number of arguments. The datum field contains the procedure being called, the type field contains the number of arguments that the procedure accepts, and the operands field contains a list of the arguments that were passed to the procedure.

    (car 3 4)                               error-->
    ;The procedure car has been called with 2 arguments;
    ; it requires exactly 1 argument.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:wrong-number-of-arguments datum type operands
  This procedure signals a condition of type `condition-type:wrong-number-of-arguments`. The datum, type and operands fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:datum-out-of-range datum
  This type indicates the class of errors in which a program discovers an object that is of the correct type but is otherwise out of range. Most often, this type indicates that an index to some data structure is outside of the range of indices for that structure. The datum field contains the offending object.

    (error:datum-out-of-range 3)            error-->
    ;The object 3 is not in the correct range.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:datum-out-of-range datum
  This procedure signals a condition of type `condition-type:datum-out-of-range`. The datum field of the condition is filled in from the corresponding argument to the procedure.

condition type: condition-type:bad-range-argument datum operator operand
  This type indicates that a procedure was passed an argument that is of the correct type but is otherwise out of range. Most often, this type indicates that an index to some data structure is outside of the range of indices for that structure. The operator field contains the procedure (or a symbol naming the procedure), the operand field indicates the argument position that was involved (this field contains either a symbol, a non-negative integer, or `#f`), and the datum field is the offending argument.

    (string-ref "abc" 3)                    error-->
    ;The object 3, passed as the second argument to string-ref,
    ; is not in the correct range.
    ;To continue, call RESTART with an option number:
    ; (RESTART 2) => Specify an argument to use in its place.
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:bad-range-argument datum operator
  This procedure signals a condition of type `condition-type:bad-range-argument`. The datum and operator fields of the condition are filled in from the corresponding arguments to the procedure; the operand field of the condition is set to `#f`.

condition type: condition-type:inapplicable-object datum operands
  This type indicates an error in which a program attempted to apply an object that is not a procedure. The object being applied is saved in the datum field, and the arguments being passed to the object are saved as a list in the operands field.

    (3 4)                                   error-->
    ;The object 3 is not applicable.
    ;To continue, call RESTART with an option number:
    ; (RESTART 2) => Specify a procedure to use in its place.
    ; (RESTART 1) => Return to read-eval-print level 1.

condition type: condition-type:file-error filename
  This is an abstract type. It indicates that an error associated with a file has occurred. For example, attempting to delete a nonexistent file will signal an error. The filename field contains a filename or pathname associated with the operation that failed.

condition type: condition-type:file-operation-error filename verb noun reason operator operands
  This is the most common condition type for file system errors. The filename field contains the filename or pathname that was being operated on. The verb field contains a string which is the verb or verb phrase describing the operation being performed, and the noun field contains a string which is a noun or noun phrase describing the object being operated on. The reason field contains a string describing the error that occurred. The operator field contains the procedure performing the operation (or a symbol naming that procedure), and the operands field contains a list of the arguments that were passed to that procedure. For example, an attempt to delete a nonexistent file would have the following field values:

      filename        "/zu/cph/tmp/no-such-file"
      verb            "delete"
      noun            "file"
      reason          "no such file or directory"
      operator        file-remove
      operands        ("/zu/cph/tmp/no-such-file")

  and would generate a message like this:

      (delete-file "/zu/cph/tmp/no-such-file") error-->
      ;Unable to delete file "/zu/cph/tmp/no-such-file" because:
      ; No such file or directory.
      ;To continue, call RESTART with an option number:
      ; (RESTART 3) => Try to delete the same file again.
      ; (RESTART 2) => Try to delete a different file.
      ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:file-operation-error filename verb noun reason operator operands
  This procedure signals a condition of type `condition-type:file-operation-error`. The fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:derived-file-error filename condition
  This is another kind of file error, which is generated by obscure file-system errors that do not fit into the standard categories. The filename field contains the filename or pathname that was being operated on, and the condition field contains a condition describing the error in more detail. Usually the condition field contains a condition of type `condition-type:system-call-error`.

procedure: error:derived-file filename condition
  This procedure signals a condition of type `condition-type:derived-file-error`. The filename and condition fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:port-error port
  This is an abstract type. It indicates that an error associated with a I/O port has occurred. For example, writing output to a file port can signal an error if the disk containing the file is full; that error would be signalled as a port error. The port field contains the associated port.

condition type: condition-type:derived-port-error port condition
  This is a concrete type that is signalled when port errors occur. The port field contains the port associated with the error, and the condition field contains a condition object that describes the error in more detail. Usually the condition field contains a condition of type `condition-type:system-call-error`.

procedure: error:derived-port port condition
  This procedure signals a condition of type `condition-type:derived-port-error`. The port and condition fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:variable-error location environment
  This is an abstract type. It indicates that an error associated with a variable has occurred. The location field contains the name of the variable, and the environment field contains the environment in which the variable was referenced.

condition type: condition-type:unbound-variable location environment
  This type is generated when a program attempts to access or modify a variable that is not bound. The location field contains the name of the variable, and the environment field contains the environment in which the reference occurred.

    foo                                     error-->
    ;Unbound variable: foo
    ;To continue, call RESTART with an option number:
    ; (RESTART 3) => Specify a value to use instead of foo.
    ; (RESTART 2) => Define foo to a given value.
    ; (RESTART 1) => Return to read-eval-print level 1.

condition type: condition-type:unassigned-variable location environment
  This type is generated when a program attempts to access a variable that is not assigned. The location field contains the name of the variable, and the environment field contains the environment in which the reference occurred.

    foo                                     error-->
    ;Unassigned variable: foo
    ;To continue, call RESTART with an option number:
    ; (RESTART 3) => Specify a value to use instead of foo.
    ; (RESTART 2) => Set foo to a given value.
    ; (RESTART 1) => Return to read-eval-print level 1.

condition type: condition-type:arithmetic-error operator operands
  This is an abstract type. It indicates that a numerical operation was unable to complete because of an arithmetic error. (For example, division by zero.) The operator field contains the procedure that implements the operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure.

condition type: condition-type:divide-by-zero operator operands
  This type is generated when a program attempts to divide by zero. The operator field contains the procedure that implements the failing operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure.

    (/ 1 0)
    ;Division by zero signalled by /.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:divide-by-zero operator operands
  This procedure signals a condition of type `condition-type:divide-by-zero`. The operator and operands fields of the condition are filled in from the corresponding arguments to the procedure.

condition type: condition-type:floating-point-overflow operator operands
  This type is generated when a program performs an arithmetic operation that results in a floating-point overflow. The operator field contains the procedure that implements the operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure.

condition type: condition-type:floating-point-underflow operator operands
  This type is generated when a program performs an arithmetic operation that results in a floating-point underflow. The operator field contains the procedure that implements the operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure.

condition type: condition-type:primitive-procedure-error operator operands
  This is an abstract type. It indicates that an error was generated by a primitive procedure call. Primitive procedures are distinguished from ordinary procedures in that they are not written in Scheme but instead in the underlying language of the Scheme implementation. The operator field contains the procedure that implements the operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure.

condition type: condition-type:system-call-error operator operands system-call error-type
  This is the most common condition type generated by primitive procedures. A condition of this type indicates that the primitive made a system call to the operating system, and that the system call signalled an error. The system-call error is reflected back to Scheme as a condition of this type, except that many common system-call errors are automatically translated by the Scheme implementation into more useful forms; for example, a system-call error that occurs while trying to delete a file will be translated into a condition of type `condition-type:file-operation-error`. The operator field contains the procedure that implements the operation (or a symbol naming the procedure), and the operands field contains a list of the arguments that were passed to the procedure. The system-call and error-type fields contain symbols that describe the specific system call that was being made and the error that occurred, respectively; these symbols are completely operating-system dependent.

condition type: condition-type:control-error
  This is an abstract type. It describes a class of errors relating to program control flow.

condition type: condition-type:no-such-restart name
  This type indicates that a named restart was not active when it was expected to be. Conditions of this type are signalled by several procedures that look for particular named restarts, for example `muffle-warning`. The name field contains the name that was being searched for.

    (muffle-warning)                        error-->
    ;The restart named muffle-warning is not bound.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

procedure: error:no-such-restart name
  This procedure signals a condition of type `condition-type:no-such-restart`. The name field of the condition is filled in from the corresponding argument to the procedure.

condition type: condition-type:not-loading
  A condition of this type is generated when the procedure `current-load-pathname` is called from somewhere other than inside a file being loaded.

    (current-load-pathname)                 error-->
    ;No file being loaded.
    ;To continue, call RESTART with an option number:
    ; (RESTART 1) => Return to read-eval-print level 1.

condition type: condition-type:warning
  This is an abstract type. All warnings should inherit from this type. Warnings are a class of conditions that are usually handled by informing the user of the condition and proceeding the computation normally.

condition type: condition-type:simple-warning message irritants
  This is the condition generated by the `warn` procedure. The fields message and irritants are taken directly from the arguments to `warn`; message contains an object (usually a string) and irritants contains a list of objects. The reporter for this type uses `format-error-message` to generate its output from message and irritants.

condition type: condition-type:simple-condition message irritants
  This is an unspecialized condition that does not fall into any of the standard condition classes. The message field contains an object (usually a string) and irritants contains a list of objects. The reporter for this type uses `format-error-message` to generate its output from message and irritants.

condition type: condition-type:breakpoint environment message prompt
  A condition of this type is generated by the breakpoint mechanism. The contents of its fields are beyond the scope of this document.

[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated by Chris Hanson on June, 17 2002 using texi2html