[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Lazy catch behaviour
From: |
Neil Jerram |
Subject: |
Lazy catch behaviour |
Date: |
11 May 2001 16:52:03 +0100 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7 |
When documenting lazy-catch last week, I was surprised to discover
that it _does_ unwind the dynamic context back to the `lazy-catch'
before invoking the handler. It seemed to me that, if it doesn't
unwind the stack, it would be consistent also not to unwind the
dynamic context.
Today, I discovered a weird consequence of the current behaviour,
while playing around with the evaluator traps support. If I set a
trivial enter-frame-handler, and then enable enter-frame trapping, the
REPL goes into an infinite loop bouncing between the inside and the
outside of the `dynamic-wind' in the readline.scm implementation of
`repl-reader'.
Here's exactly what I do to see this:
guile> (set! enter-frame-handler (lambda args (write args) (newline)))
guile> (trap-enable 'enter-frame)
[Using exit-frame instead produces the same behaviour BTW:
guile> (set! exit-frame-handler (lambda args (write args) (newline)))
guile> (trap-enable 'exit-frame)
]
So the effective overall pattern is:
(lazy-catch #t
(lambda ()
...
(dynamic-wind (lambda ()
;; read in-guard
...)
(lambda ()
(read))
(lambda ()
;; read out-guard
...)))
(lambda args
(write args)
(newline)))
What I think happens is:
1. For every frame in the evaluation of the in-guard, the enter frame
handler is called and prints the result. Note that the dynamic
wind isn't yet active until the in-guard has completed.
2. Evaluation begins of the dynamic-wind thunk, but before it gets
very far, we throw to the enter frame handler.
3. Before reaching the enter frame handler, we must invoke the
out-guard. The enter frame handler is called for every frame in
the out-guard thunk.
4. Finally we get to the enter frame handler for the first frame of
the inner thunk, which prints its args and then returns, so we wind
back through the in-guard, calling the frame handler for every
frame ...
5. Repeat for the next frame in the inner thunk ...
6. Somewhere in the middle of all this, readline throws an error to
the effect that it is not reentrant. This error is caught by the
REPL, which then loops ...
Two things emerge from all this:
1. Is the current lazy-catch behaviour useful? Certainly not in this
case, and for most uses of the evaluator trap handlers that I can
imagine. Can anyone suggest any cases where it is positively
useful to unwind the dynamic context before invoking the lazy catch
handler? I realize that we have to be careful about making sure
that the lazy-catch is not active during the execution of its own
handler, but couldn't we special-case that?
On the other hand, if we don't unwind the dynamic context, a lazy
catch handler call is basically just the same as calling the
handler inline instead of the throw. Could the evaluator trap
handlers be implemented as simple procedure calls rather than
by throwing exceptions?
2. There's a readline reentrancy bug in there somewhere.
Thoughts?
Neil
- Lazy catch behaviour,
Neil Jerram <=