Dynamic scoping

Allen Wirfs-Brock Allen_Wirfs-Brock at Instantiations.com
Fri Jan 31 23:09:57 UTC 2003

At 11:46 PM 1/30/2003 -0500, Anthony Hannan wrote:
>Allen Wirfs-Brock <Allen_Wirfs-Brock at Instantiations.com> wrote:
> > The topic at hand is dynamic "variable" scoping.
>I prefer messages to variables because they are more powerful and
>general.  It allows more sophisticated queries, instead of just
>returning a fixed value.  I guess I'm just proposing another form of
>exception handling, where exceptions are distinguished by selector
>instead of class, that is why I reused #on:do:.
>I even like to think of global variables as messages sent to Smalltalk
>or the class's environment/pool.  Like Self, no variables just objects
>and messages.

The reason I quoted "variable" above is because the majority of the recent 
discussions and proposals concerning "dynamic scoping" have not been about 
scoping actual variable references but about a mechanism and message 
protocol for creating a dynamically scoped name/value association context. 
Almost all the proposals I have seen use some message protocol to 
accomplish this.  The only alternative would be to change the Smalltalk 
language (and hence compiler's) definition of variable reference such that 
they are dynamically rather than lexically scoped. For now, I will simply 
assert that this would be a bad idea.

Something you may want to consider is what constitutes the difference 
between a language extension and a new language.  A good language extension 
should add the desired functionality in a way that is both program and 
programmer compatible with the existing language. In the absence of it's 
use, an extension shouldn't change the behavior of any existing programs 
and probably even more importantly, it shouldn't change any programmer's 
conceptual understanding of the language. If an extension doesn't have 
these characteristics then what you are actually doing is defining a new 
language.  This may be appropriate in some circumstances but if that is 
what you are doing you need to be up front about it. "Self" is a 
Smalltalk-like language but it is clearly a different language. If you want 
to define a new Smalltalk-like language that is your prerogative, but don't 
try to sneak it in as part of a focused functional extension to the 
existing language.

You still seem to want to have some sort of commonality between exception 
handling and dynamic "variable" scoping. I suspect this is your language 
implementor persona getting in the way of your language designer persona. 
Clearly, exception handlers use a dynamic scoping mechanism and it has been 
demonstrated that dynamically scoped name/value associations (fluids would 
be a fine shorthand for that phrase) can be implemented using the Smalltalk 
exception mechanism. However, that doesn't mean that exceptions and fluids 
are the same thing. I assert that a programmer who needs to establish an 
exception handling context is thinking about something very different from 
a programmer who needs to establish a fluid binding context.   You will 
only create confusion, if you try to make them look the same.

Equating exceptions and fluids would also unnecessarily limit your 
implementation alternatives. It would not be at all surprising to discover 
that the usage patterns of exceptions and fluids are quite different and 
call for differing optimization strategies. For example, you might discover 
that "shallowing bind" mechanisms are better suited for one and "deep 
binding" mechanisms for the other.

Another good language design rule is to optimize the design of a feature 
for its most common usage. In this case I'm pretty confident that the most 
common usage would be a fixed value binding.  While an "active value"  (a 
block evaluation) is more powerful, it isn't going to be the most common 
usage. By requiring a block for the bound value you are complicating the 
most common usage and introducing likely error scenarios that would not 
exist for fixed values.  It's fine to provide an alternative "active value" 
form but don't force everybody to use it all the time.

>To satisfy your design principles, we could change the syntax to:
>         Context bind: #world toDo: [myWorld] during: [self bar].
>         Context world.
>Context would be an object that only understands #bind:toDo:during: and
>#doesNotUnderstand:.  #doesNotUnderstand: would search the sender chain
>for the first #bind:toDo:during: context for the message's selector and
>execute its toDo: block.  I believe this syntax satisfies the design
>principles you mention below.

Aside from the block as the second argument, my main concern is the 
#doesNotUnderstand: trickery.  Another good Smalltalk design principle is: 
don't use #doesNotUnderstand: to create surface syntax.  The virtual 
machine implementor will have made optimization trade-offs based upon 
observed or projected usage of #doesNotUnderstand:.  What if the usage 
patterns of fluids are very different from those and suggest the need of a 
higher level of optimization?  In your design, you don't have a local 
optimization alternative.  You are going to have to tackle optimizing 

So, my preference (using this vocabulary) would be:

         Context bind: #world to: myWorld during: [self bar].  "ok to keep 
#bind:toDo:during: as an alternative"

         Context bindingOf: #world.

If your concern is the verbosity of #bindingOf: I would go with the symbol 
based protocol:

         #world bindTo: myWorld during: [self bar].

         #world binding

I suspect that the verbosity is probably not really a big issue as I 
suspect that most of these binding should be encapsulated in other methods. 
For example you might expect Morphic class to define:

use: aWorld during: aBlock
         ^Context bind: #world to: aWorld during: aBlock.

         w := Context bindingOf: #world.
         w ~~ nil ifTrue: [^w] ifFalse: [^World]

Allen_Wirfs-Brock at Instantiations.com

More information about the Squeak-dev mailing list