My namespace proposal described in Yet Another Try

Göran Krampe goran at krampe.se
Wed Sep 19 07:53:10 UTC 2007


Hi folks!

I just typed this in, longish but hopefully enlightening, forgive me for
any typos etc.

regards, Göran
------------
I agree, syntax is not really important. And we have already discussed it
AT LENGHT at earlier occasions. To all of you out there that think this is
the *first* Namespace-discussion on Squeak-dev - you have no idea... :)

Compile time binding vs late binding:
Currently we have compile time binding of class names, I think moving away
from that as the "default" is too much of a change.
And at the times we want to do late binding we can already use obvious
Smalltalk code (in both our proposals): MyNamespace at: #Array

Let me try to explain a bit about my proposed solution (and yes, it is on
SqueakMap and *works* almost completely, updated for 3.9 IIRC):

I have written about it on numerous occasions and every time it feels like
a lot of people either misunderstand it, don't think it *is* a namespace
solution at all, don't even try to understand it or all of the above. :) I
am not sure why, but I think it has at least *partially* to do with people
being so fixated on how "other languages do it" that they can't even begin
to consider an alternative approach. If you read this, please try to open
up your mind and consider that there ARE other ways to do it. :)

Ok, (rubbing head to come up with the ultimate pedagogical approach),
let's begin with a few "Intentions" with this proposal:

- Simple. I mean, dead simple. :)
- Backwards compatible. Tools should work etc etc.
- Not disrupt the "feel" of Smalltalk. Read more below.

Now... Michael is IMHO implementing a rather "regular" namespace solution,
as so many others have done or tried doing over the years. That may be
fine - and from what I know he is doing it as part of a larger project so
he probably have good reasons for its design. My proposal is solely aimed
at being a lightweight-just-enough-solution only aimed at Squeak and its
community and not rooted in any other project. In other words - there is
NO other use of my code and effort than getting it eventually accepted in
Squeak - otherwise it is totally wasted. ;)

Let's look at "Simple" first. In my proposal I am proposing that we "go
with the flow" and evolve what we already have. What *do* we have then? We
have a shared global space (SystemDictionary) and other spaces created by
various participants in our community (prefixes). Examples are WA for
Seaside, SM for SqueakMap and so on. Let's consider that for a second - we
actually *already have* a Namespace solution in place which works!
Prefixes. I can hear people thinking "Is he on crack or what, that's not
namespaces..." - but I challenge you: Why not?

Just because lots of people over the years have for various reasons
decided to make namespaces==package (or some other concept) does not mean
that a Namespace IS a package or any other source code or deployment
entity. A Namespace is "just a space of names" - a Dictionary simply.
Please agree with me on that. :) A named space that is a cooperatively
maintained set of unique names.

If we agree on this then the scope of problems we are trying to solve is
made much smaller and comprehensible:

- Allowing duplicate names in an image.
- Being able to write short names and read short names.
- Being able to manipulate namespaces like remapping or moving names
between them etc.

It does not deal with deployment units, method overrides, source code
management etc etc!

Now, let's look at the prefixes used today then:

- It is not hierarchical! It is simple "a bunch of named buckets". But
that is exactly what was needed! So saying that namespaces MUST be
hierarchical is ignoring the fact that what we have today actually works.
- Binding is compile time, just as with globals. Hey, WAComponent is of
course also a global, since the solution today is just plain prefixing.

I am proposing:

- Allow "::" (or hey, any other nice separator that we can agree on - it
is NOT that important) in global names. This is a very small change and we
have done it (Andreas and I) and it works.
- Implement class Namespace and let it act just like a Dictionary and let
us create one instance "per prefix" automatically. This is the reification
part of my proposal so that:

	Fruit::Orange == (Smalltalk at: #Fruit) at: #Orange
	Fruit::Orange == Fruit at: #Orange
	Fruit class == Namespace

Thus our namespaces are globals and we can easily do nice dynamic lookup
using "Fruit at: #Orange" if we like. We can also easily check for
Namespaces being there with "Smalltalk at: #Fruit ifAbsent: []" and we can
manipulate our namespaces and classes within them etc. IMHO the obvious
Smalltalk way - I presume Michael's solution in this respect is similar.

BUT... Andreas advised me *strongly* to let my Namespace instances
delegate to Smalltalk (the SystemDictionary) because otherwise tons of
code will break. So my Namespace instances behave like Dictionary but
actually don't hold anything at all! The class is *still held in
Smalltalk* just like before:

	(Smalltalk at: #Fruit::Orange) == Fruit::Orange

At this point people may be confused but it all boils down to this usage
pattern:

	- If you want to have a class Apple in your own namespace "Fruit", just
name it "Fruit::Apple"! It is that simple.
	- If you want to move it, just rename it! The Namespace instances I
describe are automatically created and maintained.
	- If you want to use it, just type "Fruit::Apple" (because hey, that is
the name of the class!) but of course, you don't want to type all that so
fine, just type "Apple" and it will automatically work! Different things
will happen then:
		- If there is no other Apple in your image it will just work. Apple. No
prefix needed. This covers 98% I guess.
		- If there are multiple Apple, Squeak will ask you which one you mean
(nice popup menu) and autoexpand it in place!
		- If there are multiple Apple BUT one of them is in your LOCAL namespace
(=the namespace of the class you are editing) then it will work just
fine with the short form, the local Apple is chosen instead of the
others. This covers perhaps 70% of those last 2%. :)

Let me repeat that: If you consider what I wrote above you will only write
(and read) fully qualified names (Fruits::Apple) if and only if there are
multiple Apples in your image (and I bet there aren't - 98% (?) of all
classes have most likely unique short names!) AND the method you are
editing is in a class in a namespace that does NOT have one of them (it is
not local).

Please let this sink in. This means we have NO IMPORTS and we still don't
need to write or read qualified names! How is this done?

Let's compare to Java. In java we avoid typing long names by typing the
paths once at the top of the file - the imports. Then we can use short
names in the rest of the file. This is classic. Anyone who knows Eclipse
and the alt-shift-o key combo knows that you ever hardly edit the imports
section because Eclipse *will do it for you* if you press that key combo!
So in Eclipse/Java you can emulate my proposal by pressing alt-shift-o
every minute (perhaps add a background process that does it? :)) and only
type short names! Yep, same effect. The only difference is that instead of
encoding the qualified names by splitting out the tedious long paths into
an imports section - in my proposal we simple *don't*! We use qualified
long names ALL THE TIME in the source. You can do that in java too - but
it would look like hell and be awful to type.

The trick is to let the source use fully qualified names at ALL TIMES and
just hook into the source code pane rendering code and the source code
editing code and make sure the tools "render" short names and accept short
names when being typed. Aha! So the trick is in the tools. The actual
source code is JUST LIKE BEFORE. And that is why my proposal is so darn
backwards compatible.

And the simplicity of this is very powerful. Every class reference is
fully qualified. If you add ten Apples in your image the old references
will still refer perfectly to the Apple they intended (Stephane's use
case), but suddenly they will *render* fully qualified since you otherwise
would not know which one they refer to. And if you remove 9 Apples the
references still around will suddenly render *short* again.

Another example, if you move a class from one namespace to another - that
is equal to a class rename operation - and Squeak already handles renames
rather gracefully - by offering all methods it is referenced to that you
can change them. Or using RB it can fix the references for you - I haven't
tested this but I bet this works PERFECTLY FINE with my proposal!

I hope my ramblings here have shown that my proposal is indeed VERY
SIMPLE, has NO IMPORTS, still avoids typing and reading of long names,
still are REAL namespaces (you can make an Apple and so can I) and is very
backwards compatible (hey, even old fileout formats should work just fine
and Monticello and all our other tools).

But what did I mean with "Smalltalk feel"? I meant that in Smalltalk we
don't have "modes". We can type a snippet of code anywhere and just run it
- the only thing that is context sensitive is "self" so to speak. But if
we start messing with java-ish conventional namespaces with imports we
suddenly have lost that "loving feeling" - we will have lots of "modes".
The snippet will bind and behave very differently based on where I run it.
Which class? What imports does it have? What does OrderedCollection
actually bind to? And how does a Workspace work? And what imports does the
debugger have and the inspectors and all other text panes? Please consider
this.

regards, Göran




More information about the Squeak-dev mailing list