Object: Identity vs. Environment

sourcery squeak-dev.sourcery at forum-mail.net
Thu May 29 08:20:08 UTC 2003


On Thu, 29 May 2003 00:21:40 -0700, Joel Shellman <joel at ikestrel.com> 
wrote:

> So... you're agreeing with me to a certain degree as far as not using
> #isFoo?

Yes.  One should not be adding #isX methods to Object for all X.  But it's
the right thing to do in some cases.  Reasonable people will disagree where
to draw the line.  I'll probably disagree with myself at time T-sub-0 and
at time T-sub-1.

>> Adding methods to SmallInter or Symbol that "do the right thing" in
>> the case of performing operations involving SmallIntegers or Symbols
>> would result in a large number of rather esoteric methods being added
>> to SmallInteger and Symbol--because both those classes are so 
>> fundamental
>> and widely used.  So for both those protocols, it is better to have
>> #isSymbol and #isInteger methods in Object.  However, in the case of
>> Esoteric, it is better to add a #performProtocolDependentOp method to
>> Esoteric,
>> and move the protocol-dependent code to that method (invoked when needed
>> by sending #performProtocolDependentOp to the appropriate objects),
>> instead of adding #isEsoteric to Object and having protocol-dependent
>> logic send #isEsoteric as necessary.
>
> Sorry, I didn't follow what you're saying here.

Let's say we have a "map"-like object, with two methods that lookup values
based on a key.  Unfortunately, some class designer, who enjoyed the 1960's
a bit too much, added two different methods by which to lookup values. One
is called #atStringKey: and the other is called #atTextKey:.  The first one
will only work right if the argument is a String, and the second will only
work right if the argument is a Text (this is bizarre, of course, but that
reflects my belief that these situations usually result because of 
someone's
bad design.)  So in order to correctly perform lookups from this "map," we
need to know for each key whether it is a String or a Text:

	value := aKey isString
			ifTrue: [map atStringKey: aKey]
			ifFalse: 				[aKey isText
					ifTrue: [map atTextKey: aKey]]

One way to make this code more elegant would be to add the method #valueIn: 
to both String and Text:

String>valueIn: aMap
	^aMap atStringKey: self

Text>valueIn: aMap
	^aMap atTextKey: self

Then, we need merely code 'aKey valueIn: aMap', and not concern ourselves 
with
whether or not the key is a Stirng or a Text.

Whether or not this is a good idea depends on the degree of esotericity of 
the
class (protocol) implemented by our "map-like" object.  If it's relatively
esoteric, then we probably shouldn't add the #valueIn: methods to String 
and
Text, because these classes are too fundamental to be polluted by such 
esoteric
methods.  On the other hand, if our "map-like" object is relatively non- 
esoteric,
then adding the #valueIn: methods as above may be a great design choice 
(assuming
we can't just change the map class to have a protocol that's less insane.)

If we decide not to add the #valueIn: methods to String and Text, then we 
may need to consider whether or not to add #isString and #isText to Object, 
or else to
simply use #conformsToProtocol:.  In this case, both String and Text are so
fundamental and widely used, it makes sense to have #isString and #isText 
methods
in Object.

> I realized just after I sent it that it would be two as you say. So what
> you're saying is that it is ONLY an optimization? If so, why not just use
> Object>>#respondsTo? That should be able to have the same performance as 
> a
> method dispatch shouldn't it? It is conceptually equivalent to
> Object>>#isFoo, and it still similarly distinguishes everything that is a
> Foo and everything that isn't. This sort of thing is the equivalent of
> marker interfaces in Java.

The #respondsTo: method is just as bad as checking for inclusion of a 
protocol name
in a Set of protocols: it attempts to look up the method in the 
MethodDictionary by actually sending the #includesKey: message to a 
Dictionary, instead of doing the lookup entirely in the VM (as is done in a 
message send.)  And of course, #includesKey:
is implemented by sending yet other messages, which are implemented by 
sending
yet other messages, and so on.  The same is true of #includes:, which is 
what would
be used to check whether a protocol name is a member of a Set of protocol 
names.

Type some example code into a workspace, and use the debugger to step 
through the entire
thread of execution involved in performing a #respondsTo: operation.  Count 
the number
of message sends.  You'll be surprised.

--Alan

-- 
The Stupid Party thinks everyone else is evil.  The Evil Party thinks 
everyone else is stupid.



More information about the Squeak-dev mailing list