[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