Object: Identity vs. Environment

Richard A. O'Keefe ok at cs.otago.ac.nz
Wed Jun 4 00:20:06 UTC 2003


Lothar Schenk <lothar.schenk at gmx.de> wrote:
	I agree with you in principle, but there is still something
	wrong here.  Object has no business knowing anything about
	Fooness, and so it shouldn't provide a method to test
	specifically for Fooness, even if it is only lexically suggested
	that it do so.

I guess the fundamental issue is whether you believe
that "Object has no business knowing anything about Fooness"
is an absolute moral law or simply a practical guideline.

Myself, I'm not too fussed about #isFoo methods in Object
because I think it's only a practical guideline, and I do
not believe that the #isFoo methods in Object are doing enough
harm to worry about.

When Squeak gets some kind of "package" system so that
(a) methods are labelled with the package they belong to and
(b) packages have documentation strings you can view and
(c) Browsers are aware of packages
then I think it will be rather hard to argue that
Object/Foo should not have an #isFoo method.

Even now it is rather hard to argue this.
Let's take "#isColor" as our example.
It is really literally TRUE that most objects are not colours.
Putting "isColor ^false" in Object has to be better than
putting "isColor ^false" in hundreds if not thousands of
other classes.  It's better for Object to "know" that most
objects are not colours than for every one of *my* classes
to have to "know" that most objects are not colours.


	It is nevertheless true that all objects should
	have a generic method for checking if the particular instance in
	question has Fooness, but not only specifically for Fooness, but
	also for any other criterion of belonging to a particular set.
	
	The keyword here is parameterization.
	
	So why not do it this way:
	
	Object>>fulfills: aCriterion
            ^false
	
	Foo>>fulfills: aCriterion
            ^aCriterion = #Fooness
            "Note that one can just as well react to more than one criterion"
	
	Color>>fulfills: aCriterion
            ^aCriterion = #Colorness
	
Coupling.  *Coupling*.  COUPLING!

_That's_ why not do it that way.  You are telling me
"don't have #isFoo and #isColor in Object,
 have one method which does BOTH."
That is, to avoid a handful of harmless methods, you
are proposing coupling unrelated methods on a large scale.

The cure is worse than the disease.

	This is similar to the case when I would ask you if you were a
	Kroogleswank.  If you are not a Kroogleswank you needn't even
	know what a Kroogleswank is to reply that you are not.

Things are not that simple.  Suppose I ask you
"He tangata a koe?"  (Art thou a "tangata"?)
If you say "never heard of them, so I'll answer 'false'",
you'd give the wrong answer.  ("tangata" = person, human being.)

It's not enough to say "well, you can't be a tangata without
KNOWING that you are a tangata", because that isn't really true.
You might have

    Person>>
        fulfills: aSymbol
            ^#(personhood materiality heatfulness mobility
               actorhood billability ......) includes: aSymbol

which says nothing about being a tangata.  So what can I do to
make your code work with mine?  That's right, add

    isTangata
        ^self fulfills: #personhood

to Object.  Why Object?  Well, Kzin and PiersonsPuppeteer might also
claim to fulfill #personhood, without inheriting from Person.  Come
to think of it, so would a Grog claim #personhood, without having
#mobility, while Outsiders might lack #heatfulness.

	So, your example above would be written the following way (using #Colorness as 
	the criterion for things which behave like colors):
	
	Color>> = aColor
	    (aColor fulfills: #Colorness) ifFalse: [^false].
	    ^aColor privateRGB = rbg and: [
	     aColor privateAlpha = self privateAlpha]
	
	Apparently, this is no more complex than it was before,

Actually, in my eyes it is significantly more complex than before.

	but this version has the advantage that only those classes that
	either provide or use (check for) Fooness need to know anything
	about it, while Object itself never needs to know anything about
	Fooness, Colorness or whatever, as it should be.

You have forgotten inheritance.  Instead of simply writing

    fulfills: aSymbol
        ^aSymbol == #Colorness

in Color, one would have to write

    fulfills: aSymbol
        ^aSymbol == #Colorness or: [super fulfills: aSymbol].

That is, every method which asserts that instances of a class have
some property would be MORE complicated than the corresponding
#isFoo method would have been.

	And we can scrap all the myriad isThis and isThatOrOther in
	Object for one simple generic method.
	
The simplicity is an entire fiction, based on not seriously considering
multiple predicates and multiple classes.  You're talking about a very
nastily coupled predicate, each of whose implementations would be more
complicated than corresponding #isFoo implementations, which would be
markedly less efficient than the present scheme.  Complexity after
complexity, loss after loss, to avoid what isn't really any big problem.

I suppose we all agree that you should think hard about alternatives
before adding an #isFoo method in Object.  It is one of the strengths
of Smalltalk that if classes C1, C2, ..., Cn all need a #meerbleschatz
method, it DOESN'T have to be in their nearest common ancestor.  You
shouldn't add a method to Object just because it is needed in two
classes that have no nearer common ancestor.

I suppose we all agree that methods in Object should be exceptionally
well documented; in particular an #isXYZ method should make it quite
clear what answering 'true' commits the receiver to.

I suppose we all agree that other things being equal, coupling between
otherwise unrelated methods (the combination-pool-table-and-washing-machine
strategy) is best avoided.

Where we differ is, I imagine, in our judgement about whether
#isBar methods in Object are such a great evil that even a complex
coupled hack is more tolerable.



More information about the Squeak-dev mailing list