[R6RS] Timeline for R6RS SRFIs

feeley at iro.umontreal.ca feeley
Wed Jun 1 22:37:09 EDT 2005

Quoting William D Clinger <will at ccs.neu.edu>:

> Marc wrote:
> > The following topics are not yet ripe for SRFIzation...
> > 
> > - Exceptions
> > - Binary I/O
> Exceptions are already described by SRFIs 34, 35, and 36.
> So far as I know, what we're considering for exceptions
> is pretty much a subset of those SRFIs.  If that remains
> true, then a new SRFI for exceptions would seem redundant.
> Will

You are probably right, but I like the idea of presenting to the
community our complete plans for R6RS.  If there are differences
with what is specified in SRFIs 34 to 36, the community will have
the opportunity to voice their opinion on the changes.

Let me explain what I dislike about SRFI 34's handling of exceptions
(I'll comment on the other SRFIs at another time).  The specification
for raise is:

   (raise obj) 

     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-exception-handler that installed the handler being called. The
     handler's continuation is otherwise unspecified.

To me this is strange because I expect raise to either not touch the
dynamic environment, or to unwind it to the dynamic environment of the
enclosing guard, but in the SRFI 34 specification it does a mix of
both (unwinding for the exception handler, and not touching the rest
of the dynamic environment).  This leads to unexpected behavior, for
example consider:

   (with-output-to-file "X"
     (lambda ()
       (guard (exc
                  (display "an exception was raised\n")

If you look at this code you expect the output generated by the call
to some-computation to go to the file "X", and if an exception is
raised during the call to some-computation the message "an exception
was raised\n" will go to the file "X".  But in fact this is not the
case with SRFI 34.  Just consider this definition of some-computation:

   (define (some-computation)
     (with-output-to-file "Y"
       (lambda ()
         (raise "ooops")

This will send the message "an exception was raised\n" to the file
"Y"!  For consistency, all the dynamic environment (exception handler
and all other dynamic bindings such as the current output port and
"parameters" in general) should be brought back to the dynamic
environment in effet at the enclosing "guard".  In other words, guard
captures the continuation and raise invokes this continuation, thus
unwinding the dynamic environment.

The expression

       (guard (exc
                  (display "an exception was raised\n")

would be equivalent (ignoring multiple values) to:

       (let ((result
                (lambda (unwind)
                  (parameterize ((current-exception-handler
                                  (lambda (obj) (unwind (vector obj)))))
                    (list (some-computation)))))))
         (if (pair? result) ; escape or normal return?
             (car result)
             (let ((exc (vector-ref result 0)))
               (display "an exception was raised\n")

In addition to this change of semantics, for R6RS I propose we drop
with-exception-handler which can lead to infinite recursion when the
exception handler raises an exception.  So there would be only
"guard" and "raise".  Given this, it would be impossible for the
call to "raise" to return.

I'm not saying that with-exception-handler isn't an interesting
primitive to have in a Scheme system, but to use it properly you
really have to know what you are doing and know some internals of the
Scheme system you are using.  with-exception-handler is just too
low-level and bug prone for standardization in R6RS.  Anyway,
guard/raise as I propose cover 99% of the expected uses of


This mail sent through IMP: http://horde.org/imp/

More information about the R6RS mailing list