Email list hosting service & mailing list manager

flow of control issues Tom Lord (26 Dec 2003 18:53 UTC)
Re: flow of control issues Michael Sperber (27 Dec 2003 16:21 UTC)

flow of control issues Tom Lord 26 Dec 2003 19:17 UTC

The draft quite sanely protects C code from always having to cope with
multiple returns (not to mention state-saving) as via upward
continuations.  C code should not, however, be _prevented_ from
constructing an upwards continuation.

The draft is silent on tail call optimization which is an unfortuante
omission that limits, for example, the kinds of higher-order
procedures that can be implemented using the FFI.

It's silent about asynchronous interrupts which, while not standard
Scheme, are likely to be an important feature of most
implementations.  In an interactive application especially, absense of
support for asynchronous interruption in "built-in" procedures can
spoil an application's usability.

It uses non-local exits for errors which raises the unwind-protection
issues I mentioned earlier.

I would therefore like to suggest the draft be revised on four

1) Don't use non-local exits for errors.   Instead, provide a
   mechanism for returning error codes.   If Scheme return values are
   to be passed via output parameters, then there is a convenient
   interface for this:

	error_code = SCHEME_CAR (&return_value, instance, &pair);
        if (error_code)
            /* clean up and return an error to our caller */
            return error_code;
        /* otherwise, continue normally.  The call to CAR
         * succeeded.

   In addition to avoiding non-local exits in the FFI, this style of
   error handling is closer to what is customary in C.

2) Do provide polling for asynchronous interruption.

   As in:

	while (very_long_loop)
            if (SCHEME_INTERRUPT_POLL (instance))
                /* cleanup and return early */
                return SCHEME_ERR_INTERRUPT;

3) Do provide a "trampoline-on-the-ceiling" style of tail calls for C.

   As in:

        fn ( [...] )

          /* instead of returning a value, something vaguley like:

          SCHEME_CONSTRUCT_APPLICATION (&result, instance, &proc,
                                        &arg1, &arg2, ...);

          return SCHEME_ERR_MAKE_TAILCALL;

   in which case my caller is responsible for performing the procedure
   application I constructed.

   While certainly not as fast as what an implementation can do
   internally, such tail calls are at least safe-for-space and

   The converse of that is that the FFI needs to specify how to
   call a function which might request the caller to complete a
   tail call.

4) Do provide upward continuations from C.

   I don't have an interface sketch but, briefly, while the
   current interfaces for call-outs are fine, it should also
   be possible to write a C primitive that accepts as input a
   first-class representation of its continuation and returns
   the same.

   Used in a manner similar to the mechanism shown above for
   tail calls, this can permit FFI-using primitives whose
   state can be captured in an upward continuation.