Allison
Here is pseudocode for a possible implementation:
throw:
maybe call a hook here for handler tracing.
rebind the handlers list to a new copy of the value [1].
while there are handlers left {
pop the next handler from the current binding.
invoke it.
}
pop the (now empty) new handler list binding.
if nonfatal (because there's a continuation?) {
just return.
}
elsif debugging is appropriate (defined how?) {
invoke the debugger.
}
else {
die hard.
}
This has some advantages:
1. The set of bound handlers is easily introspected in PIR. (Not
that introspecting closures is currently of much use, but that can
change.)
2. The handlers are removed from the dynamic environment without
affecting other aspects of the dynamic environment, and are
automatically restored to the right thing when C<throw> is exited,
either normally, or by calling a continuation, or whatever (but see
drawback 3 below).
3. If the above pseudocode is implemented in PIR as a library
routine (as it easily could be), then the C substrate doesn't have to
keep track of exceptions that are in the process of being thrown.
4. In fact, and unless I have missed something additional that Perl
6 requires, this makes C<throw> completely re-entrant, in that the
throwing of multiple exceptions could be nested, or even interleaved via
coroutines and/or continuation calling.
And also some drawbacks:
1. Exception handling might be slowed down somewhat wrt a pure C
implementation.
2. It makes PDD23 depend on dynamic binding, which is even more in
the "vapor" stage.
3. When a handler invokes a continuation, the the dynamic
environment will be unwound to the continuation's scope, causing
C<push_dynscope> thunks to be invoked *in the original handler context*.
If an inner C<push_dynscope> causes the same class of error, the very
same handler might be re-invoked. This is logically consistent, but
wierd, and may not be acceptable [2]. If not, I'm not sure what to do
about it.
However, I believe this gives the best semantics for the long haul.
Indeed, I can't think of another good way to implement this, though I
may be blinkered by my Lisp experience: The pseudocode above could have
been written for the CMUCL implementation of SIGNAL.
Thoughts?
-- Bob Rogers
(trying not to be a vapor designer)
http://rgrjr.dyndns.org/
[1] The copy can be avoided if the handlers are kept in a Pair list.
[2] The ANSI CL spec is silent about this behavior (AFACS), but I
believe that CMUCL does work this way.
<montgomery-burns> Excellent. </montgomery-burns>
Mad properties to Allison for creating the first draft (updating is so much
easier than starting from scratch!) and to Bob Rogers for explaining to me
the Common Lisp perspective on EH. Most languages have something worth
learning from, and I like CL's EH. Now if it only had continuations.... }:-)
BTW, for those of you keeping score at home, refining namespaces will come
before exception implementaiton. Exceptions are important, but if you can't
even find your variables, you're pretty much up the creek.
--
Chip Salzenberg <ch...@pobox.com>
> One way to ensure that a handler is not in scope
> when invoked (though possibly not the only way) is to keep the list of
> active handlers in a dynamic variable binding.
Here's what I don't understand. Why is there talk of a stack to keep track of
various flow control constructs? Doesn't a CPS system use a linked list of
continuations to handle normal flow control? If that works there, why not
another linked list of continuations to handle exceptional flow control?
-- c
I would ultimately like to see exceptions head down that road. But an
exceptions stack is a good first approximation, and is at least safer
than the current combined control+exceptions stack.
(CPS is, BTW, a part of Parrot internals in need of more documentation.)
Allison
chromatic wrote:
> Here's what I don't understand. Why is there talk of a stack to keep track of
> various flow control constructs? Doesn't a CPS system use a linked list of
> continuations to handle normal flow control? If that works there, why not
> another linked list of continuations to handle exceptional flow control?
Both are implemented as linked lists, now and for the (to me)
conceivable future. For most purposes, though, they behave like stacks.
Furthermore, the codebase uses identifiers like "control_stack",
"Stack_Entry", etc, so I have fallen into the habit of calling them
"stacks". I think it would be good to change at least some of these
names, but changing my habits of speech may take longer. :-/
(And my apologies to chromatic for not replying sooner; the original
post got buried, and I lost track of the fact that I hadn't replied.)
I would ultimately like to see exceptions head down that road. But an
exceptions stack is a good first approximation, and is at least safer
than the current combined control+exceptions stack.
(CPS is, BTW, a part of Parrot internals in need of more documentation.)
Allison
Two weeks ago I started writing something I had been thinking about for
a year now, tentatively called "Continuations, Coroutines, And All That:
An informal introduction to creating advanced control structures in
Parrot." It is still mostly an outline, though -- it's hard to write a
tutorial about features for which the spec is in flux. ;-}
-- Bob
Aye, there's a balance between design moving too quickly (so the system
is perceived as "unstable") and design moving too slowly (so the system
is perceived as "dead"). Somewhere in the middle is the sweet spot. For
a little while here design is going to be moving a little faster, to
fill in a few gaps and clear up a few lingering questions. Then it'll
settle back out to a slow, steady pace.
The best thing you can do is just write the tutorial, or at least write
up notes on what you plan to include. Reading through it will likely
help us see pieces that don't work as well as they should, and then we
can update the spec and the tutorial together.
Allison
Bob Rogers wrote:
> Two weeks ago I started writing something I had been thinking about for
> a year now, tentatively called "Continuations, Coroutines, And All That:
> An informal introduction to creating advanced control structures in
> Parrot." It is still mostly an outline, though -- it's hard to write a
> tutorial about features for which the spec is in flux. ;-}
Aye, there's a balance between design moving too quickly (so the system
is perceived as "unstable") and design moving too slowly (so the system
is perceived as "dead"). Somewhere in the middle is the sweet spot.
Reminds me of the following .sig quote seen on the "cmucl-imp" list:
# There is this special biologist word we use for 'stable'.
# It is 'dead'. -- Jack Cohen
Hooray for instability!
For a little while here design is going to be moving a little faster,
to fill in a few gaps and clear up a few lingering questions. Then
it'll settle back out to a slow, steady pace.
No problem.
The best thing you can do is just write the tutorial, or at least
write up notes on what you plan to include. Reading through it will
likely help us see pieces that don't work as well as they should, and
then we can update the spec and the tutorial together.
Allison
Indeed, it's been driving some of the questions I've been asking lately.
And, just so folks can see where I'm trying to go, here's the current
version:
http://rgrjr.dyndns.org/perl/continuations.html
I intend to populate it with working examples, all of which should
eventually go into examples/.
-- Bob