[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