[Modules] Name space semantics was: Re: Some of my thoughts
Andrew P. Black
black at cse.ogi.edu
Thu Aug 16 20:33:58 UTC 2001
At 21:16 -0400 2001.08.15, Stephen Pair wrote:
>Simple example:
>
> - "Package A" overwrites the method #add: on OrderedCollection.
> - The method doesn't work properly and brings the system to its
>knees (try it!)
I suspect that I still don't fully understand the problem. If I want
to change the meaning of add: on OrderedCollection, and I am allowed
to do so, then indeed a bug in my new method will bring the system to
its knees. How could it not? If I don't intent to change the
meaning of add: on OrderedCollection, then I refrain from compiling a
new add: method on OrderedCollection, and, presto, the system is
still happily hobbling about on its heels, as usual ;-)
OK, so suppose that I _do_ want to change OrderedCollection>>add:.
And I want to test it first. I do this by building a subclass of
OrderedCollection, redefining add:, and testing it. If I don't test
thoroughly enough, when I promote that add: method up into
OrderedCollection, the system dies horribly. This will teach me to
test more thoroughly next time.
Alternatively, I could write a new method called newAdd: on
OrderedCollection, test it, and then change its name when I'm sure
that it works. Are these approaches so bad?
Even though I don't understand the problem, I think that I do
understand the proposed solution well enough not to like it. One of
the really wonderful things about Smalltalk is that method naming and
dispatch is very simple. A message contains a selector. It's really
easy to see if two messages have the same selector, or if a method
matches a selector -- the test is essentially string equality.
Compare this with C++ or Java or .NET, where the process may be
compounded by overloading, the identity of the package that declares
the method, the number of the arguments and their classes, and, I'm
tempted to say, the phases of the moon. Why? What does all this
complexity buy these languages?
In general, then, I will argue against anything that adds complexity
to the message send and dispatch semantics, not only from the point
of view of efficiency, but mostly from the point of view of wishing
to maintain Smalltalk's conceptual elegance. That is why I like to
hang out here.
If there is a real problem that Smalltalk's mechanism's cannot
address, I will argue for dealing with it in the tools, rather than
complicating the semantics of the language. For example, suppose
that it is really essential to load two versions of the same package.
Normally, the methods changed in the second version one will just
overwrite the similarly named methods from the first, but there might
be a switch to stop this. However, setting this switch would not
change the dispatch semantics: it would re-write the source code. So
the two versions of add: would be renamed _v1_add: and _v2_add:, and
the module loader would generate a new add: method something like
this:
add: anItem
"automatically generated by the module loader on
2001.08.13 at 14:27 to allow OrderedCollection_v1 and
OrderCollection_v2 to coexist"
thisContext containsPackage: #OrderedCollection_v1
ifTrue: [ thisContext containsPackage: #OrderedCollection_v2
ifTrue: [self error: 'Operating in a
conflicting package context'].
^self _v1_add: anItem
]
^self _v2_add: anItem
The advantage of this is that it slows down only those who use it,
and that there is no magic: if I need to understand why one method is
invoked rather than another, I can just read (or step through) some
Smalltalk code.
Andrew
More information about the Squeak-dev
mailing list
|