#
Chapter 6
Exceptions and Control Flow

## 6.1 Exceptions

MzScheme supports the exception system proposed by Friedman, Haynes, and Dybvig.12 MzScheme's implementation extends that proposal by defining the specific exception values that are raised by each primitive error.

- `(raise``` `v``)` raises an exception, where `v` represents the exception being raised. The `v` argument can be anything; it is passed to the current exception handler. Breaks are disabled from the time the exception is raised until the exception handler obtains control, and the handler itself is `parameterize-break`ed to disable breaks initially; see section 6.6 for more information on breaks.

- `(current-exception-handler)` returns the current exception handler that is used by ``raise``, and `(current-exception-handler `f`)` installs the procedure `f` as the current exception handler. The ``current-exception-handler`` procedure is a parameter (see section 7.9).

  Any procedure that takes one argument can be an exception handler, but it is an error if the exception handler returns to its caller when invoked by ``raise``. If an exception handler returns, the current error display handler and current error escape handler are called directly to report the handler's mistake. Furthermore, the call to an exception handler is `parameterize`d to set `current-exception-handler` to the default exception handler, and it is `parameterize-break`ed to disable breaks.

  The default exception handler prints an error message using the current error display handler (see ``error-display-handler`` in section 7.9.1.7) and then escapes by calling the current error escape handler (see ``error-escape-handler`` in section 7.9.1.7). The call to each handler is `parameterize`d to set `error-display-handler` to the default error display handler,13 and it is `parameterize-break`ed to disable breaks. The call to the error escape handler is further parameterized to set `error-escape-handler` to the default error escape handler.

- `(`with-handlers` ((`pred` `handler`) `···`) `expr` `···`1)` is a syntactic form that evaluates the `expr` body, installing a new exception handler before evaluating the `expr`s and restoring the handler when a value is returned (or when control escapes from the expression). The `pred` and `handler` expressions are evaluated in the order that they are specified, before the first `expr` and before the exception handler is changed. The exception handler is installed and restored with `parameterize` (see section 7.9.2).

  The new exception handler processes an exception only if one of the `pred` procedures returns a true value when applied to the exception, otherwise the original exception handler is invoked (by raising the exception again). If an exception is handled by one of the `handler` procedures, the result of the entire `with-handlers` expression is the return value of the handler.

  When an exception is raised during the evaluation of `expr`s, each predicate procedure `pred` is applied to the exception value; if a predicate returns a true value, the corresponding `handler` procedure is invoked with the exception as an argument. The predicates are tried in the order that they are specified.

  Before any predicate or handler procedure is invoked, the continuation of the entire `with-handlers` expression is restored, but also `parameterize-break`ed to disable breaks. Thus, breaks are disabled by default during the predicate and handler procedures (see section 6.6), and the ``original'' exception handler is active (i.e., the one present before the `with-handlers` expression was evaluated).

  The ``exn:fail?`` procedure is useful as a handler predicate to catch all error exceptions. Avoid using `(lambda (x) #t)` as a predicate, because the `exn:break` exception typically should not be caught (unless it will be re-raised to cooperatively break). Beware, also, of catching and discarding exceptions, because discarding an error message can make debugging unnecessarily difficult.

- `(`with-handlers*` ((`pred` `handler`) `···`) `expr` `···`1)` is the same as `with-handlers`, but if a `handler` procedure is called, breaks are not explicitly disabled, and the call is in tail position with respect to the `with-handlers*` form.

The following example defines a divide procedure that returns `+inf.0` when dividing by zero instead of signaling an exception (other exceptions raised by `/` are signaled):

    (define div-w-inf
      (lambda (n d)
        (with-handlers ([exn:fail:contract:divide-by-zero?
                         (lambda (exn) +inf.0)])
          (/ n d))))

The following example catches and ignores file exceptions, but lets the enclosing context handle breaks:

    (define (file-date-if-there filename)
      (with-handlers ([exn:fail:filesystem? (lambda (exn) #f)])
        (file-or-directory-modify-seconds filename)))

### 6.1.1 Primitive Exceptions

Whenever a primitive error occurs in MzScheme, an exception is raised. The value that is passed to the current exception handler is always an instance of the `exn` structure type. Every `exn` structure value has a `message` field that is a string, the primitive error message. The default exception handler recognizes exception values with the `exn?` predicate and passes the error message to the current error display handler (see ``error-display-handler`` in section 7.9.1.7).

Primitive errors do not create immediate instances of the `exn` structure type. Instead, an instance from a hierarchy of subtypes of `exn` is instantiated. The subtype more precisely identifies the error that occurred and may contain additional information about the error. The table below defines the type hierarchy that is used by primitive errors and matches each subtype with the primitive errors that instantiate it. In the table, each bulleted line is a separate structure type. A type is nested under another when it is a subtype.

For example, reading an ill-formed expression raises an exception as an instance of `exn:fail:read`. An exception handler can test for this kind of exception using the global `exn:fail:read?` predicate. Given such an exception, an error string can be extracted using ``exn-message``, while `exn:fail:read-source` accesses a list of source locations for the error.

Fields of the built-in `exn` structure types are immutable, so field mutators are not provided. Field-type contracts are enforced through guards; for example, `(`make-exn` "Hello" #f)` raises `exn:fail:contract` because the second argument is not a continuation mark set. All built-in `exn` structure types are transparent to all inspectors (see section 4.5).

- `exn` : not instantiated directly

  > > `message` field, `immutable string` -- error message

  > > `continuation-marks` field, `mark set` -- value returned by `current-continuation-marks` immediately before the exception is raised

  - `exn:fail` : exceptions that represent errors

  > - `exn:fail:contract` : inappropriate run-time use of a function or syntactic form

> > - `exn:fail:contract:arity` : application with the wrong number of arguments

> > - `exn:fail:contract:divide-by-zero` : divide by zero

> > - `exn:fail:contract:continuation` : attempt to cross a continuation barrier

> > - `exn:fail:contract:variable` : unbound/not-yet-defined global or module variable

> >   > > `id` field, `symbol` -- the variable's identifier

> - `exn:fail:syntax` : syntax error, but not a `read` error

>   > > `exprs` field, `immutable list of syntax objects` -- illegal expression(s)

> - `exn:fail:read` : `read` parsing error

>   > > `srclocs` field, `immutable list of `srcloc`s (see section 11.2.1.1)` -- source location(s) of error

> > - `exn:fail:read:eof` : unexpected end-of-file

> > - `exn:fail:read:non-char` : unexpected non-character

> - `exn:fail:filesystem` : error manipulating a filesystem object

> > - `exn:fail:filesystem:exists` : attempt to create a file that exists already

> > - `exn:fail:filesystem:version` : version mismatch loading an extension

> - `exn:fail:network` : TCP and UDP errors

> - `exn:fail:out-of-memory` : out of memory

> - `exn:fail:unsupported` : unsupported feature

- `exn:break` : asynchronous break signal

  > > `continuation` field, `escape continuation` -- resumes from the break

In addition to the built-in structure types for exceptions, MzScheme provides one built-in structure-type property (see section 4.4):

- The `prop:exn:srclocs` property identifies exceptions that have a list of source locations, which includes `exn:fail:read` and `exn:fail:syntax`. The `exn:srclocs?` predicate recognizes structures and structure types that have the `prop:exn:srclocs` property. The `exn:srclocs-accessor` procedure takes a structure or structure type with the `exn:srclocs` property and returns a procedure; when the procedure is applied to a structure of the same type, it returns a list of `srcloc`s (see section 11.2.1.1).

Primitive procedures that accept a procedure argument with a particular required arity (e.g., ``call-with-input-file``, ``call/cc``) check the argument's arity immediately, raising `exn:fail:contract` if the arity is incorrect.

## 6.2 Errors

The procedure ``error`` raises the exception `exn:fail` (which contains an error string). The ``error`` procedure has three forms:

- `(error``)`error/symbol creates a message string by concatenating `"error: "` with the string form of `symbol`.

- `(error``` `msg-string v``` `···``)` creates a message string by concatenating `msg-string` with string versions of the `v`s (as produced by the current error value conversion handler; see section 7.9.1.7). A space is inserted before each `v`.

- `(error``` `src-symbol format-string v``` `···``)` creates a message string equivalent to the string created by:

      (format (string-append "~s: " format-string)
        src-symbol v ···)

In all cases, the constructed message string is passed to `make-exn:fail` and the resulting exception is raised.

### 6.2.1 Application Type Errors

`(raise-type-error``` `name-symbol expected-string v``)` creates an `exn:fail:contract` value and ``raise``s it as an exception. The `name-symbol` argument is used as the source procedure's name in the error message. The `expected-string` argument is used as a description of the expected type, and `v` is the value received by the procedure that does not have the expected type.

`(raise-type-error``` `name-symbol expected-string bad-k v``)` is similar, except that the bad argument is indicated by an index (from 0), and all of the original arguments `v` are provided (in order). The resulting error message names the bad argument and also lists the other arguments. If `bad-k` is not less than the number of `v`s, the `exn:fail:contract` exception is raised.

### 6.2.2 Application Mismatch Errors

`(raise-mismatch-error``` `name-symbol message-string v``)` creates an `exn:fail:contract` value and ``raise``s it as an exception. The `name-symbol` is used as the source procedure's name in the error message. The `message-string` is the error message. The `v` argument is the improper argument received by the procedure. The printed form of `v` is appended to `message-string` (using the error value conversion handler; see section 7.9.1.7).

### 6.2.3 Syntax Errors

`(raise-syntax-error``` `name message-string``` [`expr sub-expr`]`)` creates an `exn:fail:syntax` value and ``raise``s it as an exception. Macros use this procedure to report syntax errors. The `name` argument is usually `#f` when `expr` is provided; it is described in more detail below. The `message-string` is used as the main body of the error message. The optional `expr` argument is the erroneous source syntax object or S-expression. The optional `sub-expr` argument is a syntax object or S-expression within `expr` that more precisely locates the error. If `sub-expr` is provided, it is used (in syntax form) for the `exprs` field of the generated exception record, else the `expr` is used if provided, otherwise the `exprs` field is the empty list. Source location information in the error-message text is similarly extracted from `sub-expr` or `expr`, when at least one is a syntax object.

The form name used in the generated error message is determined through a combination of the `name`, `expr`, and `sub-expr` arguments. The `name` argument can `#f` or a symbol:

- `#f`: When `name` is `#f`, and when `expr` is either an identifier or a syntax pair containing an identifier as its first element, then the form name from the error message is the identifier's symbol.

  If `expr` is not provided, or if it is not an identifier or a syntax pair containing and identifier as its first element, then the form name in the error message is `"?"`.

- `symbol`: When `name` is a symbol, then the symbol is used as the form name in the generated error message.

See also section 7.9.1.7.

### 6.2.4 Inferred Value Names

To improve error reporting, names are inferred at compile-time for certain kinds of values, such as procedures. For example, evaluating the following expression:

    (let ([f (lambda () 0)]) (f 1 2 3))

produces an error message because too many arguments are provided to the procedure. The error message is able to report ``f'' as the name of the procedure. In this case, MzScheme decides, at compile-time, to name as `f` all procedures created by the `let`-bound `lambda`.

Names are inferred whenever possible for procedures. Names closer to an expression take precedence. For example, in

    (define my-f
      (let ([f (lambda () 0)]) f))

the procedure bound to `my-f` will have the inferred name ``f''.

When an `'inferred-name` property is attached to a syntax object for an expression (see section 12.6.2), the property value is used for naming the expression, and it overrides any name that was inferred from the expression's context.

When an inferred name is not available, but a source location is available, a name is constructed using the source location information. Inferred and property-assigned names are also available to syntax transformers, via `syntax-local-name`; see section 12.6 for more information.

`(object-name``` `v``)` returns a value for the name of `v` if `v` has a name, `#f` otherwise. The argument `v` can be any value, but only (some) procedures, structs, struct types, struct type properties, regexp values, and ports have names. The name of a procedure, struct, struct type, or struct type property is always a symbol. The name of a regexp value is a string, and a byte-regexp value's name is a byte string. The name of a port is typically a path or a string, but it can be arbitrary. All primitive procedures have names (see section 3.12.2).

## 6.3 Continuations

MzScheme supports fully re-entrant `call-with-current-continuation` (or `call/cc`). The macro `let/cc` binds a variable to the continuation in an immediate body of expressions:

     (let/cc k expr ···1)
    =expands=>
     (call/cc (lambda (k) expr ···1))

Capturing a continuation also captures the current continuation marks (see section 6.5) and parameterization (see section 7.9). A continuation can be invoked from the thread (see Chapter 7) other than the one where it was captured. Multiple return values can be passed to a continuation (see section 2.2).

MzScheme installs a continuation barrier around evaluation in the following contexts, preventing full-continuation jumps across the barrier:

- applying an exception handler, an error escape handler, or an error display handler (see section 6.1);

- applying a macro transformer (see section 12.6), evaluating a compile-time expression, or applying a module name resolver (see section 5.4.1);

- applying a custom-port procedure (see section 11.1.7), an event guard procedure (see section 7.7), or a parameter guard procedure (see section 7.9);

- applying a security-guard procedure (see section 9.1);

- applying a will procedure (see section 13.3); or

- evaluating or loading code from the stand-alone MzScheme command line (see section 17).

In addition, extensions of MzScheme may install barriers in additional contexts. In particular, MrEd installs a continuation barrier around most every callback. Finally, `(call-with-continuation-barrier``` `thunk``)` applies `thunk` with a barrier between the application and the current continuation.

In addition to regular ``call/cc``, MzScheme provides `call-with-escape-continuation` (or `call/ec`) and `let/ec`. A continuation obtained from ``call/ec`` can only be used to escape back to the continuation; i.e., an escape continuation is only valid when the current continuation is an extension of the escape continuation. The application of ``call/ec``'s argument is not a tail call.

Escape continuations are provided for two reasons: 1) they are significantly cheaper than full continuations; and 2) they can cross continuation boundaries (which full continuations cannot cross).

The `exn:fail:contract:continuation` exception is raised when a continuation application would cross a continuation barrier, or an escape continuation is applied outside of its dynamic scope.

## 6.4 Dynamic Wind

`(dynamic-wind``` `pre-thunk value-thunk post-thunk``)` applies its three thunk arguments in order. The value of a ``dynamic-wind`` expression is the value returned by `value-thunk`. The `pre-thunk` procedure is invoked before calling `value-thunk` and `post-thunk` is invoked after `value-thunk` returns. The special properties of ``dynamic-wind`` are manifest when control jumps into or out of the `value-thunk` application (either due to an exception or a continuation invocation): every time control jumps into the `value-thunk` application, `pre-thunk` is invoked, and every time control jumps out of `value-thunk`, `post-thunk` is invoked. (No special handling is performed for jumps into or out of the `pre-thunk` and `post-thunk` applications.)

When ``dynamic-wind`` calls `pre-thunk` for normal evaluation of `value-thunk`, the continuation of the `pre-thunk` application calls `value-thunk` (with ``dynamic-wind``'s special jump handling) and then `post-thunk`. Similarly, the continuation of the `post-thunk` application returns the value of the preceding `value-thunk` application to the continuation of the entire ``dynamic-wind`` application.

When `pre-thunk` is called due to a continuation jump, the continuation of `pre-thunk`

1. jumps to a more deeply nested `pre-thunk`, if any, or jumps to the destination continuation; then

2. continues with the context of the `pre-thunk`'s ``dynamic-wind`` call.

Normally, the second part of this continuation is never reached, due to a jump in the first part. However, the second part is relevant because it enables jumps to escape continuations that are contained in the context of the ``dynamic-wind`` call. Furthermore, it means that the continuation marks (see section 6.5) and parameterization (see section 7.9) for `pre-thunk` correspond to those of the `dynamic-wind` call that installed `pre-thunk`. The `pre-thunk` call, however, is `parameterize-break`ed to disable breaks (see also section 6.6).

Similarly, when `post-thunk` is called due to a continuation jump, the continuation of `post-thunk` jumps to a less deeply nested `post-thunk`, if any, or jumps to a `pre-thunk` protecting the destination, if any, or jumps to the destination continuation, then continues from the `post-thunk`'s ``dynamic-wind`` application. As for `pre-thunk`, the parameterization of the original `dynamic-wind` call is restored for the call, and the call is `parameterize-break`ed to disable breaks.

Example:

    (let ([v (let/ec out
               (dynamic-wind
                (lambda () (display "in "))
                (lambda ()
                  (display "pre ")
                  (display (call/cc out))
                  #f)
                (lambda () (display "out "))))])
      (when v (v "post ")))
     ; => displays in pre out in post out

    (let/ec k0
      (let/ec k1
        (dynamic-wind
         void
         (lambda () (k0 'cancel))
         (lambda () (k1 'cancel-canceled)))))
     ; => 'cancel-canceled

    (let* ([x (make-parameter 0)]
           [l null]
           [add (lambda (a b)
                  (set! l (append l (list (cons a b)))))])
      (let ([k (parameterize ([x 5])
                 (dynamic-wind
                     (lambda () (add 1 (x)))
                     (lambda () (parameterize ([x 6])
                                  (let ([k+e (let/cc k (cons k void))])
                                    (add 2 (x))
                                    ((cdr k+e))
                                    (car k+e))))
                     (lambda () (add 3 (x)))))])
        (parameterize ([x 7])
          (let/cc esc
            (k (cons void esc)))))
      l) ; => '((1 . 5) (2 . 6) (3 . 5) (1 . 5) (2 . 6) (3 . 5))

## 6.5 Continuation Marks

To evaluate a sub-expression, MzScheme creates a continuation for the sub-expression that extends the current continuation. For example, to evaluate ``expr1`` in the expression

    (begin
      expr1
      expr2)

MzScheme extends the continuation of the `begin` expression with one continuation frame to create the continuation for ``expr1``. In contrast, ``expr2`` is in tail position for the `begin` expression, so its continuation is the same as the continuation of the `begin` expression.

A continuation mark is a keyed mark in a continuation frame. A program can install a mark in the first frame of its current continuation, and it can extract the marks from all of the frames in any continuation. Continuation marks support debuggers and other program-tracing facilities; in particular, continuation frames roughly correspond to stack frames in traditional languages. For example, a debugger can annotate a source program to store continuation marks that relate each expression to its source location; when an exception occurs, the marks are extracted from the current continuation to produce a ``stack trace'' for the exception.

The list of continuation marks for a key `k` and a continuation `C` that extends `C0` is defined as follows:

- If `C` is an empty continuation, then the mark list is ``null``.

- If `C`'s first frame contains a mark `m` for `k`, then the mark list for `C` is `(cons `m` `l0`)`, where `l0` is the mark list for `k` in `C0`.

- If `C`'s first frame does not contain a mark keyed by `k`, then the mark list for `C` is the mark list for `C0`.

The `with-continuation-mark` form installs a mark on the first frame of the current continuation:

    (with-continuation-mark key-expr mark-expr
       body-expr)

The `key-expr`, `mark-expr`, and `body-expr` expressions are evaluated in order. After `key-expr` is evaluated to obtain a key and `mark-expr` is evaluated to obtain a mark, the key is mapped to the mark in the current continuation's initial frame. If the frame already has a mark for the key, it is replaced. Finally, the `body-expr` is evaluated; the continuation for evaluating `body-expr` is the continuation of the `with-continuation-mark` expression (so the result of the `body-expr` is the result of the `with-continuation-mark` expression, and `body-expr` is in tail position for the `with-continuation-mark` expression).

The ``continuation-marks`` procedure extracts the complete set of continuation marks from a continuation, and The ``continuation-mark-set->list`` procedure extracts mark values for a particular key from a continuation mark set. The complete set of continuation-mark procedures follows:

- `(continuation-marks``` `cont``)` returns an opaque value containing the set of continuation marks for all keys in the continuation `cont`. If `cont` is an escape continuation (see section 6.3), then the current continuation must extend `cont`, or the `exn:fail:contract` exception is raised.

- `(current-continuation-marks``)` returns an opaque value containing the set of continuation marks for all keys in the current continuation. In other words, it produces the same value as `(`call-with-current-continuation` `continuation-marks`)`.

- `(continuation-mark-set->list``` `mark-set key-v``)` returns a newly-created list containing the marks for `key-v` in `mark-set`, which is a set of marks returned by ``current-continuation-marks``.

- `(continuation-mark-set->list*``` `mark-set key-list``` [`none-v`]`)` returns a newly-created list containing vectors of marks in `mark-set` for the keys in `key-list`. The length of each vector in the result list is the same as the length of `key-list`, and a value in a particular vector position is the value for the corresponding key in `key-list`. Values for multiple keys appear in a single vector only when the marks are for the same continuation frame in `mark-set`. If `none-v` is supplied, it is used for vector elements to indicate the lack of a value; the default is `#f`.

- `(continuation-mark-set-first``` `optional-mark-set key-v``)` returns the first element of the list that would be returned by `(`continuation-mark-set->list` (or optional-mark-set (`current-continuation-marks`)) key-v)`, or `#f` if the result would be the empty list. Typically, this result can be computed more quickly using `continuation-mark-set-first`.

- `(continuation-mark-set?``` `v``)` returns `#t` if `v` is a mark set created by ``continuation-marks`` or ``current-continuation-marks``, `#f` otherwise.

Examples:

    (define (extract-current-continuation-marks key)
       (continuation-mark-set->list
        (current-continuation-marks)
        key))

    (with-continuation-mark 'key 'mark
      (extract-current-continuation-marks 'key)) ; => '(mark)

    (with-continuation-mark 'key1 'mark1
      (with-continuation-mark 'key2 'mark2
        (list
         (extract-current-continuation-marks 'key1)
         (extract-current-continuation-marks 'key2)))) ; => '((mark1) (mark2))

    (with-continuation-mark 'key 'mark1
      (with-continuation-mark 'key 'mark2 ; replaces the previous mark
        (extract-current-continuation-marks 'key)))) ; => '(mark2)

    (with-continuation-mark 'key 'mark1
      (list ; continuation extended to evaluate the argument
       (with-continuation-mark 'key 'mark2
          (extract-current-continuation-marks 'key)))) ; => '((mark1 mark2))

    (let loop ([n 1000])
      (if (zero? n)
          (extract-current-continuation-marks 'key)
          (with-continuation-mark 'key n
            (loop (sub1 n))))) ; => '(1)

In the final example, the continuation mark is set 1000 times, but `extract-current-continuation-marks` returns only one mark value. Because `loop` is called tail-recursively, the continuation of each call to `loop` is always the continuation of the entire expression. Therefore, the `with-continuation-mark` expression replaces the existing mark each time rather than adding a new one.

Whenever MzScheme creates an exception record, it fills the ``continuation-marks`` field with the value of `(current-continuation-marks)`, thus providing a snapshot of the continuation marks at the time of the exception.

When a continuation procedure returned by ``call-with-current-continuation`` is invoked, it restores the captured continuation, and also restores the marks in the continuation's frames to the marks that were present when ``call-with-current-continuation`` was invoked.

## 6.6 Breaks

A break is an asynchronous exception, usually triggered through an external source controlled by the user, or through the `break-thread` procedure (see section 7.3). A break exception can only occur in a thread while breaks are enabled. When a break is detected and enabled, the `exn:break` exception is raised in the thread sometime afterward; if breaking is disabled when ``break-thread`` is called, the break is suspended until breaking is again enabled for the thread. While a thread has a suspended break, additional breaks are ignored.

Breaks are enabled through the ``break-enabled`` parameter-like procedure, and through the `parameterize-break` form, which is analogous to `parameterize` (see section 7.9). The ``break-enabled`` procedure does not represent a parameter to be used with `parameterize`, because changing the break-enabled state of a thread requires an explicit check for breaks, and this check is incompatible with the tail evaluation of a `parameterize` expression's body.

- `(break-enabled``` [`on?`]`)` -- gets or sets the break enabled state of the current thread. If `on?` is not supplied, the result is `#t` if break are currently enabled, `#f` otherwise. If `on?` is supplied as `#f`, breaks are disabled, and if `on?` is a true value, breaks are enabled.

- `(parameterize-break boolean-expr expr `···`1)` evaluates `boolean-expr` to determine whether breaks are initially enabled in while evaluating `expr`s in sequence. The result of the `parameter-break` expression is the result of the last `expr`.

  Like `parameterize` (see section 7.9), a fresh thread cell (see section 7.8) is allocated to hold the break-enabled state of the continuation, and calls to `break-enabled` within the continuation access or modify the new cell.

- `(current-break-parameterization``)` is analogous to `(current-parameterization)` (see section 7.9); it returns a break-parameterization (effectively a thread cell) that holds the current continuation's break-enable state.

- `(call-with-break-parameterization``` `break-param thunk``)` is analogous to `(call-with-parameterization parameterization thunk)` (see section 7.9); it calls `thunk` in a continuation whose break-enabled state is in `break-param`. The `thunk` is not called in tail position with respect to the `call-with-break-parameterization` call.

Certain procedures, such as ``semaphore-wait/enable-break``, enable breaks temporarily while performing a blocking action. If breaks are enabled for a thread, and if a break is triggered for the thread but not yet delivered as an `exn:break` exception, then the break is guaranteed to be delivered before breaks can be disabled in the thread. The timing of `exn:break` exceptions is not guaranteed in any other way.

Before calling a `with-handlers` predicate or handler, an exception handler, an error display handler, an error escape handler, an error value conversion handler, or a `pre-thunk` or `post-thunk` for a ``dynamic-wind`` (see section 6.4), the call is `parameterize-break`ed to disable breaks. Furthermore, breaks are disabled during the transitions among handlers related to exceptions, during the transitions between `pre-thunk`s and `post-thunk`s for ``dynamic-wind``, and during other transitions for a continuation jump. For example, if breaks are disabled when a continuation is invoked, and if breaks are also disabled in the target continuation, then breaks will remain disabled until from the time of the invocation until the target continuation executes unless a relevant ``dynamic-wind`` `pre-thunk` or `post-thunk` explicitly enables breaks.

If a break is triggered for a thread that is blocked on a nested thread (see ``call-in-nested-thread``), and if breaks are enabled in the blocked thread, the break is implicitly handled by transferring it to the nested thread.

When breaks are enabled, they can occur at any point within execution, which makes certain implementation tasks subtle. For example, assuming breaks are enabled when the following code is executed,

    (with-handlers ([exn:break? (lambda (x) (void))])
      (semaphore-wait s))

then it is not the case that a void result means the semaphore was decremented or a break was received, exclusively. It is possible that both occur: the break may occur after the semaphore is successfully decremented but before a void result is returned by ``semaphore-wait``. A break exception will never damage a semaphore, or any other built-in construct, but many built-in procedures (including ``semaphore-wait``) contain internal sub-expressions that can be interrupted by a break.

In general, it is impossible using only ``semaphore-wait`` to implement the guarantee that either the semaphore is decremented or an exception is raised, but not both. MzScheme therefore supplies ``semaphore-wait/enable-break`` (see section 7.4), which does permit the implementation of such an exclusive guarantee:

    (parameterize ([break-enabled #f])
      (with-handlers ([exn:break? (lambda (x) (void))])
        (semaphore-wait/enable-break s)))

In the above expression, a break can occur at any point until break are disabled, in which case a break exception is propagated to the enclosing exception handler. Otherwise, the break can only occur within ``semaphore-wait/enable-break``, which guarantees that if a break exception is raised, the semaphore will not have been decremented.

To allow similar implementation patterns over blocking port operations, MzScheme provides ``read-bytes-avail!/enable-break`` (see section 11.2.1), `write-bytes-avail/enable-break` (see section 11.2.2), and other procedures.

## 6.7 Error Escape Handler

Special control flow for exceptions is performed by an error escape handler that is called by the default exception handler. An error escape handler takes no arguments and must escape from the expression that raised the exception. The error escape handler is obtained or set using the `error-escape-handler` parameter (see section 7.9.1.7).

An error escape handler cannot invoke a full continuation that was created prior to the exception, but it can invoke an escape continuation (see section 6.3).

The error escape handler is normally called directly by an exception handler, in a parameterization that sets the error display and escape handlers to the default handlers, and `parametrize-break`ed to disable breaks. To escape from a run-time error, use ``raise`` (see section 6.1) or ``error`` (see section 6.2) instead.

If an exception is raised while the error escape handler is executing, an error message is printed using a primitive error printer and a primitive error escape handler is invoked.

In the following example, the error escape handler is set so that errors do not escape from a custom `read`-`eval`-`print` loop:

    (let ([orig (error-escape-handler)])
      (let/ec exit
        (let retry-loop ()
          (let/ec escape
            (error-escape-handler
             (lambda () (escape #f)))
            (let loop ()
              (let ([e (my-read)])
                (if (eof-object? e)
                    (exit 'done)
                    (let ([v (my-eval e)])
                      (my-print v)
                      (loop))))))
          (retry-loop)))
      (error-escape-handler orig))

See also ``read-eval-print-loop`` in section 14.1 for a simpler implementation of this example.

12 See http://www.cs.indiana.edu/scheme-repository/doc.proposals.exceptions.html

13 If the current error display handler is the default handler, then the error-display call is parameterized to install an emergency error display handler that attempts to print directly to a console and never fails.