R5RS had no way to signal or handle errors beyond the unspecified effect of “it is an error”. R6RS added a complete exception and condition system, R7RS-small took its exceptions and left the condition types unspecified, and implementations before then had their own (SRFI 12, 18, 34, 35 and 36 are the common ones).
Error situations in the reports
The reports distinguish what a program may do from what an implementation must do. When a report says it is an error, an implementation is not required to detect it, and the program is wrong; where it says an error is signalled or an exception is raised, the implementation must raise it. Unspecified means a value is returned but which one is not said. Implementation restrictions, such as an absence of exact rationals, may be reported by raising an exception. R6RS names a condition type for each kind of violation (below), and R7RS, which took its exceptions, left the condition types unspecified: where R6RS requires a condition of a given type, R7RS says only “it is an error”.
Raising and handling in R7RS
Any object can be raised, and any procedure of one argument can be an exception handler. The system keeps a current exception handler in the dynamic environment.
| Form or procedure | Meaning |
|---|---|
(raise obj) | Calls the current handler on obj, in the dynamic environment of the raise except that the current handler is the one in place when the called handler was installed (so a handler that raises goes to the outer handler). If the handler returns, a secondary exception is raised in the dynamic environment of the handler. It never returns normally |
(raise-continuable obj) | Like raise but the handler’s return values become the values of the call, and the handler is current again afterwards |
(with-exception-handler handler thunk) | Calls thunk with handler installed as the current handler, and returns its values |
(guard (var clause ...) body ...) | Evaluates the body; if an exception is raised, binds the object to var and evaluates the clauses as the clauses of a cond, in the continuation and dynamic environment of the guard (so the handler runs after unwinding). If no clause’s test is true and there is no else, raise-continuable is called on the object again in the dynamic environment of the original raise, so an outer handler still sees it. A clause may use => |
(error message obj ...) | Raises as if by raise an implementation-defined error object that holds message (a string) and the other objects, called the irritants |
(error-object? obj), (error-object-message e), (error-object-irritants e) | Tests for an error object and takes it apart |
(read-error? obj), (file-error? obj) | True for exceptions raised by read for a syntax error, and for file procedures that cannot open or delete a file. They may or may not satisfy error-object? |
(guard (condition
((assq 'a condition) => cdr)
((assq 'b condition)))
(raise (list (cons 'a 42)))) ; 42
(guard (e ((error-object? e)
(display (error-object-message e))
(error-object-irritants e)))
(error "bad thing:" 1 2)) ; prints bad thing:, returns (1 2)
(with-exception-handler
(lambda (con)
(cond ((string? con) (display con))
(else (display "a warning has been issued")))
42)
(lambda ()
(+ (raise-continuable "should be a number")
23))) ; prints the string, returns 65
A handler installed with with-exception-handler that returns from a call to raise causes a secondary exception, so an error handler normally escapes with a continuation, or the program uses guard, which does it for it. syntax-error (see Macros) raises at expansion time. exit and emergency-exit end the program (see I/O ports).
Conditions of R6RS
R6RS raises condition objects, records that can be combined. (rnrs conditions) defines the types and (rnrs exceptions) the handling: raise, raise-continuable, with-exception-handler and guard (with else and =>, as in R7RS, which took them), and the base library has error, assert and assertion-violation.
| Procedure | Meaning |
|---|---|
(error who message irritant ...) | Raises a &error condition (with &message, &irritants and, if who is not #f, &who). who is a symbol or string naming the reporter. In R7RS the first argument is the message |
(assertion-violation who message irritant ...) | Raises a &assertion violation, for a call with invalid arguments |
(assert expression) | Raises an assertion violation if the expression is false |
(condition c1 ...) | Makes a compound condition from several; simple-conditions takes one apart, and condition? tests |
(condition-predicate rtd), (condition-accessor rtd proc) | Make the predicate and the field accessor of a condition type from its record-type descriptor |
(define-condition-type name supertype constructor predicate field-spec ...) | Defines a condition type as a record type that extends supertype |
The standard condition types
| Type | Parent | Constructor, predicate, accessors |
|---|---|---|
&condition | (root) | the root of all condition types |
&message | &condition | make-message-condition message-condition? condition-message |
&warning | &condition | make-warning warning?; does not prohibit continuing |
&serious | &condition | make-serious-condition serious-condition?; cannot safely be ignored |
&error | &serious | make-error error?; something wrong in the program’s dealings with the outside world |
&violation | &serious | make-violation violation?; a violation of the standard or of a library, typically a programming error |
&assertion | &violation | make-assertion-violation assertion-violation?; a wrong number or type of arguments |
&irritants | &condition | make-irritants-condition irritants-condition? condition-irritants |
&who | &condition | make-who-condition who-condition? condition-who |
&non-continuable | &violation | make-non-continuable-violation non-continuable-violation?; a handler of raise returned |
&implementation-restriction | &violation | make-implementation-restriction-violation implementation-restriction-violation? |
&lexical | &violation | make-lexical-violation lexical-violation?; a syntax violation at the level of the datum syntax |
&syntax | &violation | make-syntax-violation syntax-violation? syntax-violation-form syntax-violation-subform |
&undefined | &violation | make-undefined-violation undefined-violation?; an unbound identifier |
&i/o | &error | make-i/o-error i/o-error?; the root of the I/O conditions |
&i/o-read, &i/o-write, &i/o-invalid-position, &i/o-filename, &i/o-port | &i/o | a read or write failure, an invalid port position (i/o-error-position), an error about a file name (i/o-error-filename), an error about a port (i/o-error-port) |
&i/o-file-protection | &i/o-filename | a protection failure; its child &i/o-file-is-read-only |
&i/o-file-already-exists, &i/o-file-does-not-exist | &i/o-filename | the file exists, or does not |
&i/o-decoding, &i/o-encoding | &i/o-port | a decoding error, and an encoding error with i/o-encoding-error-char |
&no-infinities, &no-nans | &implementation-restriction | infinities or NaNs cannot be represented |
R6RS says the initial exception handler handles &serious conditions by interrupting execution, reporting, and giving options, and returns when passed any other condition.
(import (rnrs))
(define (safe-div a b)
(guard (e ((and (assertion-violation? e) (who-condition? e))
(condition-who e))
((violation? e) 'violation))
(/ a b)))
(define-condition-type &my-error &error
make-my-error my-error?
(code my-error-code))
Other error systems
- SRFI 23 – the
errorprocedure that R7RS took. SRFI 12 (withdrawn) and SRFI 34 – exception handling for programs:with-exception-handler,raiseandguard, the basis of R7RS. SRFI 35 and SRFI 36 – condition types and I/O conditions. SRFI 255 and 249 – restartable conditions (249 withdrawn). SRFI 288 – a compound-condition system (draft). - MIT/GNU Scheme – a condition system with restarts,
condition/report-string,access-condition,call-with-escape-continuation; Guile –catchandthrowwith keys, and R6RS conditions; CHICKEN –condition-caseandhandle-exceptions; Gauche –guard,with-error-handlerand condition classes.
The viewer colours raise, guard, error, with-exception-handler, assert, assertion-violation, the condition constructors, predicates and accessors, and the &name types.
Not described
Known, not yet covered
- Reference: the condition systems of the implementations (the last list above) are named from memory, none of their manuals was read;
catch,throw,condition-case,handle-exceptionsandwith-error-handlerare not described, and the viewer does not colour them. - Reference: the exact conditions each R6RS procedure raises for each wrong argument are not described.
- Reference: the order of the compound condition’s components, and the R6RS
raiseversusraise-continuablehandler-return rules for non-serious conditions, are summarised, not described.
See also
- Continuations and dynamic-wind –
guardas a structured escape - Records – condition types are record types
- Standard libraries –
(rnrs conditions)and(rnrs exceptions)