[Squeak-e] Are Handlers Dynamically Scoped? (was: Comments on Lex's
"Object as Capabilities in Squeak")
Mark S. Miller
markm at caplet.com
Sat Feb 1 17:51:47 CET 2003
At 11:16 AM 1/31/2003 Friday, Anthony Hannan wrote:
>Yes, exception handling needs dynamic scope, doesn't it? Do you propose
>handling exceptions differently?
Exception handing was an aspect of PPS2.5 that I never did learn real well.
Where is Squeak's exception handling documented? As I recall, PPS2.5 had
both terminating and resumable exception handlers. Let's take these separately.
Terminating Exceptions
E uses only terminating exceptions, on the same model (for present purposes)
as C++ and Java. Since I don't remember PPS2.5's terminating exceptions
being any different from this, I'll just assume they're the same until I
hear otherwise. I will use Java as the reference for this model, as it's
probably the most mutually well known.
Java try-catch and try-finally blocks do have some semantics in common with
dynamic scoping. They push and pop on the stack according to nested dynamic
extents, just as dynamic variable bindings do. When one is needed, the
dynamically closest applicable one is looked up, presumably by looking back on
the stack, corresponding to a deeply-bound implementation of dynamic scoping.
However, I claim this isn't dynamic scoping. The "throw" is not directly
invoking the corresponding "catch". Rather, the stack is being unwound and
"finally {..}" clauses are getting run on the way out. If one of these
finally clauses itself throws, we proceed to unwind with the new Exception
*instead of* the old one. These effects fit poorly into the dynamic scoping
model.
Instead, what fits well is a simple extension of the continuation passing
model of call-return computation (CPS). When writing in a call-return
language, there's always one unstated additional parameter on all calls --
the continuation -- representing the rest of the computation the caller will
perform once the callee returns. In denotational semantics, Actors, or
Scheme, where CPS originated, the continuation was simply a function of one
argument, where this argument was the value to be returned.
(It's a separate matter as to whether the language allows the continuation
to be reified, or treats it only as an explanatory device. Smalltalk,
Scheme, and Actors do the first. C++, Java, and E do the second. For various
reasons http://www.eros-os.org/pipermail/e-lang/2001-July/005418.html I
recommend the second, but we can leave this argument to another time.)
As explained in section ii of
http://erights.org/elib/concurrency/msg-passing.html , to account for
terminating exceptions, we model the implicitly passed continuation as an
object with two methods
resolve: result
and
smash: exception
A throw just calls the smash method of its continuation. The peculiar
behavior of a try-finally is just the peculiar behavior of the continuation
it creates.
(Note: to model E we need three methods in the continuation, but I think we
can ignore that for present purposes.)
So, clever implementations aside, the computational model is explained
purely in terms of local message sending without any magic reaching up the
stack (deep binding) or stateful variables being magically shared (shallow
binding). I claim it's not dynamic scoping at all.
Resumable Exceptions
Although I may have programmed in languages that happened to support
resumable exceptions, I myself have never used them in any language. So if
this is where the "Are Handlers Dynamically Scoped?" issue is, I'll wait
until someone explains their semantics, or points me at documentation.
If these are indeed dynamically scoped, then we need to ask whether they are
a good idea.
----------------------------------------
Text by me above is hereby placed in the public domain
Cheers,
--MarkM
More information about the Squeak-e
mailing list