STklos Reference Manual

7. Exceptions and Conditions

Contents
| *Top*
1 | Introduction
2 | Expressions
3 | Program structure
4 | Standard Procedures
5 | Regular Expressions
6 | Pattern Matching

7

Exceptions and Conditions

7.1 | Exceptions
7.2 | Conditions
7.3 | Predefined Conditions

8 | STklos Object System
9 | Threads, Mutexes and Condition Variables
10 | Customizations
11 | The ScmPkg Package System
12 | Foreign Function Interface
13 | Using the SLIB package
14 | SRFIs
15 | Index
| Bibliography

### 7.1 Exceptions

The following text is extracted from SRFI-34 (Exception Handling for Programs), from which STklos exceptions are derived. Note that exceptions are part of R7RS.

Exception handlers are one-argument procedures that determine the action the program takes when an exceptional situation is signalled. The system implicitly maintains a current exception handler.

The program raises an exception by invoking the current exception handler, passing to it an object encapsulating information about the exception. Any procedure accepting one argument may serve as an exception handler and any object may be used to represent an exception.

The system maintains the current exception handler as part of the dynamic environment of the program, akin to the current input or output port, or the context for dynamic-wind. The dynamic environment can be thought of as that part of a continuation that does not specify the destination of any returned values. It includes the current input and output ports, the dynamic-wind context, and this SRFI's current exception handler.

`(with-handler <handler> <expr1> ... <exprn>)` | STklos syntax

Evaluates the sequences of expressions `<expr1>` to `<exprn>`. `<handler>` must be a procedure that accepts one argument. It is installed as the current exception handler for the dynamic extent (as determined by dynamic-wind) of the evaluations of the expressions

>     (with-handler (lambda (c)
>                     (display "Catch an error\n"))
>        (display "One ... ")
>        (+ "will yield" "an error")
>        (display "... Two"))
>            -| "One ... Catch an error"

`(with-exception-handler <handler> <thunk>)` | R7RS procedure

This form is similar to `with-handler`. It uses a thunk instead of a sequence of expressions. It is conform to SRFI-34 (Exception Handling for Programs). In fact,

>     (with-handler <handler> <expr1> ... <exprn>)

is equivalent to

>     (with-exception-handler <handler>
>       (lambda () <expr1> ... <exprn>))

`(raise obj)` | R7RS procedure

Invokes the current exception handler on `obj`. The handler is called in the dynamic environment of the call to `raise`, except that the current exception handler is that in place for the call to `with-handler` that installed the handler being called.

>     (with-handler (lambda (c)
>                  (format "value ~A was raised" c))
>        (raise 'foo)
>        (format #t "never printed\n"))
>               ⇒ "value foo was raised"

`(raise-continuable obj)` | R7RS procedure

Raises an exception by invoking the current exception handler on `obj`. The handler is called with the same dynamic environment as the call to `raise-continuable`, except that: (1) the current exception handler is the one that was in place when the handler being called was installed, and (2) if the handler being called returns, then it will again become the current exception handler. If the handler returns, the values it returns become the values returned by the call to `raise-continuable`.

>     (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 should be a number
>                     ⇒ 65

`(guard (<var> <clause1 > <clause2 > ...) <body>)` | R7RS procedure

Evaluating a guard form evaluates `<body>` with an exception handler that binds the raised object to `<var>` and within the scope of that binding evaluates the clauses as if they were the clauses of a cond expression. That implicit cond expression is evaluated with the continuation and dynamic environment of the `guard` expression. If every `<clause>`'s test evaluates to false and there is no `else` clause, then `raise` is re-invoked on the raised object within the dynamic environment of the original call to `raise` except that the current exception handler is that of the `guard` expression.

>     (guard (condition
>              ((assq 'a condition) => cdr)
>              ((assq 'b condition)))
>       (raise (list (cons 'a 42))))
>              ⇒ 42

>     (guard (condition
>              ((assq 'a condition) => cdr)
>              ((assq 'b condition)))
>       (raise (list (cons 'b 23))))
>              ⇒ (b . 23)

>     (with-handler (lambda (c) (format "value ~A was raised" c))
>       (guard (condition
>            ((assq 'a condition) => cdr)
>            ((assq 'b condition)))
>           (raise (list (cons 'x 0)))))
>              ⇒ "value ((x . 0)) was raised"

`(current-exception-handler)` | STklos procedure

Returns the current exception handler. This procedure is defined in SRFI-18 (Multithreading support).

### 7.2 Conditions

The following text is extracted from SRFI-35 (Conditions), from which STklos conditions are derived.

Conditions are values that communicate information about exceptional situations between parts of a program. Code that detects an exception may be in a different part of the program than the code that handles it. In fact, the former may have been written independently from the latter. Consequently, to facilitate effective handling of exceptions, conditions must communicate as much information as possible as accurately as possible, and still allow effective handling by code that did not precisely anticipate the nature of the exception that occurred.

Conditions available in STklos are derived from SRFI-35 and in this SRFI two mechanisms to enable this kind of communication are provided:

- subtyping among condition types allows handling code to determine the general nature of an exception even though it does not anticipate its exact nature,
- compound conditions allow an exceptional situation to be described in multiple ways.

Conditions are structures with named slots. Each condition belongs to one condition type (a condition type can be made from several condition types). Each condition type specifies a set of slot names. A condition belonging to a condition type includes a value for each of the type's slot names. These values can be extracted from the condition by using the appropriate slot name.

There is a tree of condition types with the distinguished `&condition` as its root. All other condition types have a parent condition type.

Conditions are implemented with STklos structures (with a special bit indicating that there are conditions). Of course, condition types are implemented with structure types. As a consequence, functions on structures or structures types are available on conditions or conditions types (the contrary is not true). For instance, if C is a condition, the expression

>     (struct->list C)

is a simple way to see it's slots and their associated value.

`(make-condition-type id parent slot-names)` | STklos procedure

`Make-condition-type` returns a new condition type. `Id` must be a symbol that serves as a symbolic name for the condition type. `Parent` must itself be a condition type. `Slot-names` must be a list of symbols. It identifies the slots of the conditions associated with the condition type.

`(condition-type? obj)` | STklos procedure

Returns `#t` if `obj` is a condition type, and `#f` otherwise

`(make-compound-condition-type id ct1 ...)` | STklos procedure

`Make-compound-condition-type` returns a new condition type, built from the condition types `ct1`, ... `Id` must be a symbol that serves as a symbolic name for the condition type. The slots names of the new condition type is the union of the slots of conditions `ct1` ...
Note: This function is not defined in SRFI-34.

`(make-condition type slot-name value ...)` | STklos procedure

`Make-condition` creates a condition value belonging condition type `type`. The following arguments must be, in turn, a slot name and an arbitrary value. There must be such a pair for each slot of `type` and its direct and indirect supertypes. `Make-condition` returns the condition value, with the argument values associated with their respective slots.

>     (let* ((ct (make-condition-type 'ct1 &condition '(a b)))
>            (c  (make-condition ct 'b 2 'a 1)))
>       (struct->list c))
>          ⇒ ((a . 1) (b . 2))

`(condition? obj)` | STklos procedure

Returns `#t` if `obj` is a condition, and `#f` otherwise

`(condition-has-type? condition condition-type)` | STklos procedure

`Condition-has-type?` tests if `condition` belongs to `condition-type`. It returns `#t` if any of condition 's types includes `condition-type` either directly or as an ancestor and `#f` otherwise.

>      (let* ((ct1 (make-condition-type 'ct1 &condition '(a b)))
>             (ct2 (make-condition-type 'ct2 ct1 '(c)))
>             (ct3 (make-condition-type 'ct3 &condition '(x y z)))
>             (c   (make-condition ct2 'a 1 'b 2 'c 3)))
>       (list (condition-has-type? c ct1)
>          (condition-has-type? c ct2)
>          (condition-has-type? c ct3)))
>         ⇒ (#t #t #f)

`(condition-ref condition slot-name)` | STklos procedure

`Condition` must be a condition, and `slot-name` a symbol. Moreover, `condition` must belong to a condition type which has a slot name called `slot-name`, or one of its (direct or indirect) supertypes must have the slot. `Condition-ref` returns the value associated with `slot-name`.

>     (let* ((ct (make-condition-type 'ct1 &condition '(a b)))
>            (c  (make-condition ct 'b 2 'a 1)))
>       (condition-ref c 'b))
>          ⇒ 2

`(condition-set! condition slot-name obj)` | STklos procedure

`Condition` must be a condition, and `slot-name` a symbol. Moreover, `condition` must belong to a condition type which has a slot name called `slot-name`, or one of its (direct or indirect) supertypes must have the slot. `Condition-set!` change the value associated with `slot-name` to `obj`.
Note: Whereas `condition-ref` is defined in SRFI-35, `confition-set!` is not.

`(make-compound-condition condition0 condition1 ...)` | STklos procedure

`Make-compound-condition` returns a compound condition belonging to all condition types that the `conditioni` belong to. `Condition-ref`, when applied to a compound condition will return the value from the first of the `conditioni` that has such a slot.

`(extract-condition condition condition-type)` | STklos procedure

`Condition` must be a condition belonging to `condition-type`. `Extract-condition` returns a condition of `condition-type` with the slot values specified by `condition`. The new condition is always allocated.

>     (let* ((ct1 (make-condition-type 'ct1 &condition '(a b)))
>            (ct2 (make-condition-type 'ct2 ct1 '(c)))
>            (c2  (make-condition ct2 'a 1 ' b 2 'c 3))
>            (c1  (extract-condition c2 ct1)))
>       (list (condition-has-type? c1 ct2)
>          (condition-has-type? c1 ct1)))
>           ⇒ (#f #t)

### 7.3 Predefined Conditions

STklos implements all the conditions types which are defined in SRFI-35 (Conditions) and SRFI-36 (I/O Conditions). However, the access functions which are (implicitely) defined in those SRFIs are only available if the file |"full-conditions.stk"| is loaded. This can be done with the following call

>     (require "full-conditions")

The following hierarchy of conditions is predefined:

>     &condition
>        &message (has "message" slot)
>        &serious
>        &error
>           &error-message (has "message", "location" and "backtrace" slots)
>           &i/o-error
>              &i/o-port-error (has a "port" slot)
>                 &i/o-read-error
>                 &i/o-write-error
>                 &i/o-closed-error
>             &i/o-filename-error (has a "filename" slots)
>                 &i/o-malformed-filename-error
>                 &i/o-file-protection-error
>                     &i/o-file-is-read-only-error
>                 &i/o-file-already-exists-error
>                 &i/o-no-such-file-error
>          &read-error (has the "line", "column", "position" and "span" slots)

This Html page has been produced by Skribe.
Last update Wed Nov 24 17:57:14 2021