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@instantiations.com
squeak-dev@lists.squeakfoundation.org