unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Neil Jerram <neil@ossau.uklinux.net>
Subject: Re: Backtrace and enhanced catch
Date: Wed, 01 Feb 2006 23:04:36 +0000	[thread overview]
Message-ID: <874q3i65q3.fsf@ossau.uklinux.net> (raw)
In-Reply-To: <87k6cgi2jo.fsf@zip.com.au> (Kevin Ryde's message of "Wed, 01 Feb 2006 07:07:55 +1100")

Kevin Ryde <user42@zip.com.au> writes:

>     ;; lazy-catch, but with HANDLER allowed to return
>     (define-public (c-lazy-catch key thunk handler)
>       (catch 'c-lazy-catch
>         (lambda ()
>           (lazy-catch key thunk
>                       (lambda args
>                         (throw 'c-lazy-catch (apply handler args)))))
>         (lambda (key val)
>           val)))

Thanks.  It took me a while to get my head round this, but in the end
it has helped me see how we can put some finishing touches to
catch and lazy-catch so that they are really nice, clear, consistent
and useful.

With these finishing touches, I think you would be able to write
c-lazy-catch as:

(define (c-lazy-catch key thunk handler)
  (catch key
         thunk
         noop
         handler))

The spec for catch's pre-unwind-handler would be that it can exit
either normally or non-locally.  If it exits normally, Guile unwinds
(dynamic context + stack) and then calls the normal (post-unwind)
handler.  If it exits non-locally, that exit determines the
continuation.

The spec for a lazy-catch handler would be nicely consistent with
this.  Again, we say that the lazy-catch handler can exit either
normally or non-locally.  It if exits normally, Guile itself throws
the same key and args again.  If it exits non-locally, that exit
determines the continuation.

For both cases, we need to make sure that a pre-unwind or lazy-catch
handler that rethrows (or, more generally, throws something whose key
matches its own catch/lazy-catch) does not call the same pre-unwind or
lazy-catch handler again recursively.  (For two reasons: first, to
avoid a possible infinite recursion; second, to allow an interesting
new behaviour, chained calling of lazy-catch/pre-unwind handlers up
the dynamic context.)  Guile currently does this by unwinding the
dynamic context before calling the handler, but this has the problem
that the handler does not truly run in the context where the throw
occurred.  Instead of that, we can avoid the recursion quite easily by
adding a "running" field to the lazy_catch/pre_unwind structure, and
using the scm_frame_ API to ensure that this is set when the handler
is running and reset when it is exited (either normally or
non-locally).

Existing lazy-catch handlers usually end with `(apply throw key args)'
to do a rethrow.  A nice consequence of the spec and implementation
just proposed is that such a handler (if it exits by this throw) will
behave exactly the same as if this final expression was not there.

If we implement this under the existing lazy-catch interface, there
would be 3 kinds of incompatible behaviour change.

1. A lazy-catch handler that returns normally would be equivalent to
   ending with a rethrow, whereas currently Guile does a
   scm_misc_error ("throw", "lazy-catch handler did return.",
   SCM_EOL);

2. Lazy-catch handlers would execute in the full dynamic context where
   the throw occurred, including in particular fluid values; whereas
   currently they don't.  (The only bit of dynamic context that the
   current implementation preserves is the stack.)

3. If a lazy-catch handler throws to a key that does not match its own
   lazy-catch, the proposed new implementation could match that key to
   a catch/lazy-catch that is _closer_ to the throw than the first
   lazy-catch; whereas existing Guile would always look for a
   catch/lazy-catch higher up the dynamic context.

   For example:

     (catch 'a
       (lambda ()
         (lazy-catch 'b
           (lambda ()
             (catch 'a
               (lambda ()
                 (throw 'b))
               inner-handler))
           (lambda (key . args)
             (throw 'a))))
       outer-handler)

   Current Guile would handle the (throw 'a) by calling outer-handler,
   and continuing with the continuation of the outer catch.  The
   proposed implementation would call inner-handler and continue with
   the continuation of the inner catch.

   This seems surprising at first, but I reckon it's inevitable if you
   are serious about executing lazy handlers truly lazily - i.e. in
   the full context of the original throw.

I think all these changes are sufficiently obscure that we could get
away with implementing them under lazy-catch.  But if we want to be
ultra-cautious we could keep lazy-catch as it is and introduce
`with-pre-unwind-handler' (or something) with the proposed semantics.

Anyone still reading?  What do you think?

       Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


  reply	other threads:[~2006-02-01 23:04 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-12-01  0:16 gh_inexact_p error in 1.7.x Bruce Korb
2005-12-01  0:44 ` Kevin Ryde
2005-12-05  4:08   ` No way out Bruce Korb
2005-12-05  4:35     ` Bruce Korb
2005-12-07  1:31       ` Marius Vollmer
2005-12-05 22:20     ` Kevin Ryde
2005-12-06 10:58       ` Han-Wen Nienhuys
2005-12-28 15:59         ` Neil Jerram
2005-12-31 15:09           ` Han-Wen Nienhuys
2005-12-31 15:14             ` Neil Jerram
2006-01-01 19:58               ` Han-Wen Nienhuys
2006-01-02 15:42                 ` Neil Jerram
2006-01-02 18:54                   ` Neil Jerram
2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
2006-01-14 12:41                       ` Neil Jerram
2006-01-22 13:47                         ` Marius Vollmer
2006-01-23 20:11                           ` Neil Jerram
2006-01-24 21:34                             ` Marius Vollmer
2006-01-16  8:38                       ` Ludovic Courtès
2006-01-18 23:08                         ` Neil Jerram
2006-01-19  9:38                           ` Ludovic Courtès
2006-01-21 11:26                             ` Neil Jerram
2006-01-26 23:29                       ` Kevin Ryde
2006-01-27 19:30                         ` Neil Jerram
2006-01-31 20:07                           ` Kevin Ryde
2006-02-01 23:04                             ` Neil Jerram [this message]
2006-02-04  0:46                               ` Kevin Ryde
2006-02-04 15:41                                 ` Neil Jerram
2005-12-07  1:07     ` No way out Marius Vollmer
2005-12-07  1:55       ` Rob Browning
2005-12-13 20:32         ` Marius Vollmer
2005-12-28 16:09       ` Neil Jerram

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874q3i65q3.fsf@ossau.uklinux.net \
    --to=neil@ossau.uklinux.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).