Object: Identity vs. Environment

Joel Shellman joel at ikestrel.com
Mon Jun 9 07:38:25 UTC 2003


> It gets worse.  At present, an #isFoo method can do anything it
> pleases, as long as it follows a few simple rules:
> (a) an #isFoo method, wherever placed, should be free of malign
>     side effects.
> (b) an #isFoo method should answer true or false.
> (c) an #isFoo method should never raise an exception that it doesn't
catch.

Why? Or rather, if it's there, yes certainly don't throw an exception for
such a simple thing. But if we did as you suggested down below about moving
isWebBrowser to a different class, and then someone tried to call it on a
different class, it would throw an exception. Is that okay?

> In particular, Terry Pratchett fans will understand why
>
>     angua isBeautifulWoman
>     angua isWolf
>
> have time-dependent behaviour, and the time dependency is not necessarily
> the same as the time dependency for other other object of the same class.
> (Angua is a werewolf working for the Ankh-Morpork City Watch.)
>
> And indeed, we find that the popular #isEmpty method *does* have a time
> varying result which *is* different for different objects in the same
> class.

The isEmpty is not a good example: that is a different concept. Regardless
of whether it's empty or not, it's still a collection. And notice that
#isEmpty is on Collection where (as I think anyway) it "belongs".

The other example makes some sense, but... why would you want to put
isBeautifulWoman and isWolf on Object?

> Feh!  Why should we encumber ourselves with all this appalling code
> just to eliminate isBehavior, isCollection, isColor, isFloat, isForm,
> isFraction, isInteger, isMessageSend, isMorph, isMorphicEvent, isNumber,
> isPoint, isPseudoContext, isString, isText, isTransparent,
> isVariableBinding, and isWebBrowser from Object?
>
> If someone were to say "let's clean up Behavior, CompiledMethod,
> DeepCopier, Environment, ImageSegment, LiteralNode, LiteralVariableNode,
> PackageInfo, SyntaxMorph, SystemDictionary, TilePadMorph, and VariableNode
> so that the things they apply #isVariableBinding to aren't arbitrary
> objects but come from a smaller range of objects so that
#isVariableBinding
> can move out of Object", I'd say "great!"

I don't quite follow. Why bother cleaning it up if you're saying that that
idiom is appropriate in general?

> But leaving the ability to
> say "yes I am/am not a Variable Binding" as part of the behaviour of
> every object while only making it harder to invoke and implement that
> behaviour is just silliness.  We have better things to do.

Well... I'm trying to understand the way to develop in smalltalk--best
practicies, standard idioms, etc. If the standard idiom is to put #isFoo on
Object and override it in subclasses, that would result in potentially
hundreds and eventually thousands of #isFoo's in Object. That seemed rather
odd and undesirable to me. However, if they should be avoided, then... we're
in agreement, I believe.

> Let's take #isWebBrowser.  Where is that mentioned?
> [snip]
> The third and last mention of #isWebBrowser is
>
>     TextURL>>
>     actOnClickFor: anObject

I'm glad you brought my attention to this because this is kind of what I'm
trying to figure out. Here in this single method is at least 3 different
ways of accomplishing the same concept:

** The #isFoo idiom: **
 anObject isWebBrowser
  ifTrue: [anObject jumpToUrl: url. ^ true]
** The #respondsTo idiom: **
  ifFalse: [((anObject respondsTo: #model) and: [anObject model
isWebBrowser])
    ifTrue: [anObject model jumpToUrl: url. ^ true]].

  "if it's a morph, see if it is contained in a web browser"
** The #isKindOf idiom **
  (anObject isKindOf: Morph) ifTrue: [
   m _ anObject.
   [ m ~= nil ] whileTrue: [
    (m isWebBrowser) ifTrue: [
     m  jumpToUrl: url.
     ^true ].
** The #hasProperty idiom **
    (m hasProperty: #webBrowserView) ifTrue: [
     m model jumpToUrl: url.
     ^true ].
    m _ m owner. ]
  ].

So, we have #isFoo, #respondsTo, #isKindOf, and #hasProperty. Which one is
the "correct" way of doing it? The #hasProperty could be argued that it's a
different thing (I don't know what it means at this point) so we can leave
that off for now, but the other three seem to try to accomplish the same
thing. I was already told that #isKindOf is a "bad thing".

What I'm saying is that that code smells to me. Am I right, or is there more
stuff about "the smalltalk way" that I need to understand before I'll
understand why that code is written the way it is.

> Once again, we have something probing a Morph's owner chain looking for
> a web browser.  Nothing both answers true to #isWebBrowser and is a Morph,
> it looks as though "m isWebBrowser" must always answer false.
>
> Looking at the calls of actOnClickFor:, it looks as though the argument
> is always a Model or a Morph of some kind.
>
> Perhaps
>     #getWebBrowser could move into Morph
>     #isWebBrowser could move into Model
> and with the obvious simplifications here and there, there would then
> be no need for #isWebBrowser in Object.
>
> THAT'S the way to clean up #isFoo messages in Object.

So, you're saying to move the #isFoo's off of Object and put them on
appropriate classes in the inheritance hierarchy. That was my suggestion #2.

> See, the thing is that if you add a general mechanism, what you're REALLY
> doing is evading the hard work of examining the code looking for a chance
> to clean up and *eliminate* the bad smells.

It sounds like you're agreeing with me that #isFoo is smelly. Is that
correct? I agree that putting the Dictionary on there as suggested is a "bad
idea". My original point that I'm still trying to explore is that #isFoo
smells to me.

Now that I'm at the bottom of this email I think I understand your
suggestion about suggesting cleaning up...

> If someone were to say "let's clean up Behavior, CompiledMethod,
> DeepCopier, Environment, ImageSegment, LiteralNode, LiteralVariableNode,
> PackageInfo, SyntaxMorph, SystemDictionary, TilePadMorph, and VariableNode
> so that the things they apply #isVariableBinding to aren't arbitrary
> objects but come from a smaller range of objects so that
#isVariableBinding
> can move out of Object", I'd say "great!"

makes sense. So... what I'm hearing from you is that you agree with my
suggestion #2--that #isFoo's should go in an appropriate place in the
hierarchy and not in Object. Right? Granted, there may be some select few
#isSomethingEveryObjectShouldKnow where Object really is the appropriate
place (though I admit my list might be shorter than other people's).

Thanks!

-joel



More information about the Squeak-dev mailing list