Dynamic scoping
Allen Wirfs-Brock
Allen_Wirfs-Brock at Instantiations.com
Fri Jan 31 02:25:45 UTC 2003
At 06:38 PM 1/30/2003 -0500, Anthony Hannan wrote:
>Attached is another version of my dynamic scoping and replaces the
>previous one I sent out a couple of days ago. It now looks like:
>
>foo
> [self bar] on: #world do: [myWorld].
>
>bar
> thisContext outer world.
Anthony,
I've been watching the dynamic scoping threads with some interest as it
involves a subject that I have some experience with. Also as the inventor
of the on:do:/ensure:/ifCurtailed: vocabulary I may feel a little
protective about its use (or misuse). Unfortunately, I really don't like
your above proposal so let me try to convince you to also dislike it.
The topic at hand is dynamic "variable" scoping. Let's assume that dynamic
scoping indeed would be useful to have in Squeak. Let's also assume that
dynamically scoped bindings are not intended to be a replacement for
conventional Smalltalk global "variables" (I know that such a replacement
has been suggest but it doesn't appear to be part of your proposal and
hopefully Mark Miller will finish convincing everyone that this is a bad
idea.) Given this assumption, we can talk about how we want this new
feature to appear to its users (Squeak programmers). Here are some
principles I would apply in designing such a feature:
1) It should be easy to explain the feature to a new or relatively
unsophisticated Squeak programmer.
2) A single, specific implementation technique should not be assumed
or required.
3) Usage should not require deep knowledge of low level system
implementation details.
4) Protocol vocabulary should be simple and reflect the intended usage
model.
5) Protocol vocabulary should not expose the user to the vocabulary of
the low level system implementation.
6) Protocol vocabulary should not imply or require a particular
implementation strategy for the feature.
7) A distinct feature should use a distinct vocabulary that is
different from that of other, unrelated features.
8) Don't design in "bugs waiting to happen"
9) Put the most important things first.
So let's first look at your example for establishing a dynamically scoped
binding:
>foo
> [self bar] on: #world do: [myWorld].
and examine it in light of these principles:
1) You are going to have to explain that while it looks just like
establishing an exception handler it actually means something else.
2) At the very least you require a change to the implementation of #on:do:.
3) You're maybe ok on this one but wait until we get to bar!
4)The on:do: vocabulary suggests nothing about dynamic binding, it's
scoping, etc.
5) see 3 above
6) Some sort of strong connection to exception handling is clearly implied.
7) It looks like an exception handler! If you see:
[ ] on: a do: b
(where a and b are variables) there is no clue to tell the reader the
programmer's intent.
8) The goal is to bind a particular value over some scope. However, you
aren't binding a value, you are binding a lexically scoped "function" that
computes a potentially new value each time the binding is accessed. Pitty
the poor programmer who doesn't realize that "myWorld" is assigned to
somewhere within a "bar"
9) Imagine if the receiver is a several line block. A reader won't see
that a new binding has been established until having read the entire
block. In this case, I think the establishment of the scoped binding is
the most important aspect of the feature. (I know, exception handling
#on:do seems to violate this but I would argue that when establishing an
exception context that the block to be evaluated is most important thing to
the user and should come first while the exception and its handler are
"exceptional" and hence should come second.
Now for:
>bar
> thisContext outer world.
1) I wouldn't even know where to start!!!
2) Must be implemented using contexts. Must use #messageNotUnderstood: in
its implementation.
3) Anything that references thisContext fails this criteria
4) It doesn't say anything about dynamic scoping. It's just a sequence of
messages that imply nothing.
5) see 3 above
6) see 2
7) It really doesn't have a vocabulary. It's an idiomatic usage of this
context outer and undefined messages
8) What if the name you want to find is already the name of a method in
whatever outer returns!
9) thisContext??
Hopefully, by now you are convinced. I think that some of the other ideas
for dynamic variable "syntax" probably come closer to my principles
(remember I'm only talking about the surface "syntax" of the proposals, I
reserve judgment about some of the implementation ideas). However, I can't
resist throwing out some other possibilities:
foo
Binding for:#world is: myWorld during: [self bar]
bar
Binding for: #world
Programmers with a Scheme background might perfer:
foo
(Fluid named: #world value: myWorld)
do: [self bar] "or just #named:value:do"
bar
Fluid named: world
If you want to get radical with a core system class consider:
foo
#world is: myWorld during: [self bar]
bar
#world is
etc., etc...
Anthony, keep up the good work but remember that language design and
language implementation are different tasks. When you are designing a new
language feature first think like a user and then validate it as an
implementor.
Alle_Wirfs-Brock at instantiations.com
More information about the Squeak-dev
mailing list
|