Hi!
This is pretty good.
My recollection of working with the GemStone setup was that it easily got "confusing" - BUT... that was *not primarily* because of the setup itself - but for the reason that GemStone is a multiuser environment.
In fact - if you read that post *closely* you will actually come to the conclusion that it works very, VERY similarly to my proposal - if you exclude the "multi user" aspect of it and change the lookup procedure.
It says that you have multiple "spaces" and that the space itself is in "itself" as a key. My proposal says that each space is in Smalltalk (the global space) as a key - GemStone instead has a list of spaces that it looks through one at a time.
GemStone thus has shadowing - the spaces are like layers on top of each other - a space early in the array can shadow a space later. Good? IMHO it would just get confusing and error prone *in the context of Squeak* . I simply don't see the need for shadowing like this - others may disagree - read on for an interesting side effect.
But if we disregard the above difference in lookup, they are similar:
- Both are non nested. Only one level of spaces. - Both have the spaces themselves reachable by name. - Both are compile time bound, but allows explicit runtime binding by sending messages to the "space" itself.
The example show for the latter was:
myTest := (SUnit at: #'TestCase') new.
And that code would look exactly the same in my proposal. Then James stresses that this solution hsa no syntax change - but why exactly is that a plus?
I would much rather see:
myTest := SUnit::TestCase new.
...or as it would be in 90% of the case:
myTest := TestCase new.
...than the above - when doing an explicit instantiation.
One IMHO *very* important difference with the GemStone solution is that GemStone code can bind differently when recompiled!! In my proposal all references are fully qualified in the source so they will always bind to a specific key in a specific named space. The only way to get a different result is if you have changed the value of the key - or indeed has put some other namespace at the same name (highly unlikely).
In GemStone, if you file in a package after filing in SUnit that accidentally defines #TestCase (it gets shadowed) and you later *recompile SUnit* - then it will suddenly bind to the new TestCase. Eh, oops.
As I said, I consider this to be a problem more than a feature. Having such a dynamic resolution, and NOT having imports - that seems like the worst kind of combo. ;)
Recall that GemStone is a multi user env and does not have a very active public community like Squeak has (with many public packages available). I think they are hardly comparable when it comes to use cases.
FWIW, I am totally against adding new prefixes. All classes already have an identifier that resolves them to a "package" and that is category. So the long name of Object is really Kernel- Objects:Object.
Note that suddenly giving Category a semantic meaning is a rather large backwards incompatible change. I am not saying bad or good - but it is a rather pervasive change. And I don't think they serve the same purpose.
I do propose the first part (The PI part) of the category name as the namespace name in the class creation template though - as they would probably match say 70% of the time. Mmmm, disregarding the PIs of the base image - we should probable have them on an ignore-list so that all base classes always end up by default in the global space.
Using the one class dictionary per package strategy mentioned, I think the compiler should simply prompt the user with a menu like:
Ambiguous reference to class "Widget" Foo:Widget Bar:Widget.
Which btw my proposal does. :)
It should remember this first time and resolve it that way from now on much the way it spots new message selectors and remembers that you do indeed mean that name.
That we could easily add to my proposal - a Preference or whatever. It has been discussed. Currently it has no memory and will ask each time, the only "feature" it has is that it will not ask if there is a "local" match. Again, all this is tool policy stuff - we can do it differently for every tool and every user, and top it off with 20 Preferences. :)
For the rare instance when one needs to reference two classes with the same name in different packages, one can type the optional package prefix.
Same in my proposal.
That would solve the problem nicely from a user's perspective. How to make this work is left as an exercise for the implementer. :-)
IMHO this is how it works in my proposal. I think I have already done the exercise. :) :)
regards, Göran