Object: Identity vs. Environment

Richard A. O'Keefe ok at cs.otago.ac.nz
Wed Jun 11 04:09:22 UTC 2003


I wrote:
	>The question that (anObject respondsTo: aSelector) answers is
	>    "Does anObject's class implement or inherit aSelector?"

Nevin Pratt <nevin at smalltalkpro.com> replied:
	Now wait a minute-- where'd you get that idea?

In the normal approved Squeak way:  BY READING THE CODE!

	You've just described the job of #canUnderstand:, *not* the job
	of #respondsTo:.

Have you read the implementation of #respondsTo: ?
Here's the whole thing:

    Object>>
    respondsTo: aSymbol
	"Answer whether the method dictionary of the receiver's
	 class contains aSymbol as a message selector."

	^self class canUnderstand: aSymbol

According to the method comment, #respondsTo: is supposed to do
*EXACTLY* what I said it does:  it answers whether the receiver's
class contains a particular message selector, which happens when
the class implements or inherits that selector.

	   (anObject class canUnderstand:  aSelector) answers
	"Does anObject's class implement or inherit aSelector?"

RIGHT.  And that's just exactly 100% what #respondsTo: does,
no more and no less.

	I've *never* thought of #respondsTo: in those terms.
	It's got a different job entirely.

Whatever your opinion about the job #respondsTo: has GOT,
the job it DOES is precisely the job I said it does.

	>The question that I'm always interested in is
	>    "Are there any cases where sending aSelector to anObject
	>     would not result in some kind of exception?"
	
	In other words, can the receiver handle the message that was
	sent to it.

Yes.

	That seems to me to be the common sense meaning of #respondsTo:
	-- can the receiver respond to the message sent to it,
	without throwing a MessageNotUnderstood exception.

Except for the weaselling limitation to MessageNotUnderstood,
I agree vehemently, that's what people *THINK* it's for.
If you will agree to "without throwing a MessageNotUnderstood
exception or an Error exception saying that you should _never_
send this message", then we agree 100% that that is what most
of us _want_ to ask and what many of us _think_ #respondsTo: asks.

I don't think that "self shouldNotImplement" counts as "responding"
or that a body "self error: 'rhubarb rhubarb'" counts as "responding"
in the sense that people care about.

	And that's what I've always considered the job of #respondsTo:.
	If it ever *fails* to do that, then it isn't implemented correctly.
	At least, that's my view.

Well, it hangs on what you mean by "responds to".
I don't think that a method which always raises an exception without
doing anything else, where the message basically says "don't DO that
you idiot, you should have known better" counts as "responds to".

Consider three cases:

        i := 1 to: 2.
(a)	i someElement                "from Set"
    =>  MessageNotUnderstood: someElement
(b)	i add: 3		     "from Collection"
    =>  Error: This message is not appropriate for this object
(c)     i at: 2 put: 3		     "from SequenceableCollection"
    =>  Error: you can not store into an interval

>From an "outsider" perspective, these ALL seem like failure to respond.
If I am doing
    (x respondsTo: #add:) ifTrue: [x add: 77]
in order to ensure that #add: is only called when it makes sense to call it,
then I don't *care* that the exception isn't MessageNotUnderstood, I just
care bitterly that I was unforgivably tricked into doing something that
wouldn't work.  I mean, just try and explain the difference between (a)
and (b) to a student, and then watch the lights come on: "Ohh, you mean
they put in a quick hack instead of doing the right thing?"  Yep.

Of course, since the byte codes are there, it would be possible to
implement a message

    Object>>honestlyRespondsTo: aSymbol
        if self respondsTo: aSymbol
        and the byte code doesn't start with whatever the byte codes
            for "self shouldNotImplement" or "self error: '...'"
            may be.

Rather than do that, I've learned to live without #respondsTo:.

	>I have disliked and avoided #respondsTo: ever since I realised that
	>it never told me what I really wanted to know.

I repeat, it *never* tells me what *I* really want to know.
I have never cared whether sending a message would provoke
MessageNotUnderstood or not; I have only cared whether sending
the message would always provoke *some* error or not.
To be honest, I was astonished that #shouldNotImplement _doesn't_
report MessageNotUnderstood, and still don't really understand why not.

	As a specific example (and, as I've posted before), if 
	#doesNotUnderstand: is overridden, then #respondsTo: should be 
	overridden too.  This is just like the situation where #hash should be 
	overridden if #= is overridden.  In both cases, they are inseparable 
	pairs that should be considered together.
	
Agreed.

	But I've *never* thought that (anObject respondsTo:  aSelector)
	should answer "Does anObject's class implement or inherit
	aSelector".  I use #canUnderstand:  for that.  And if
	#respondsTo:  isn't answering what it should, I tend to want to fix it.
	
But in the system as distributed, the distinction you make between
#respondsTo: and #canUnderstand: does not exist; one calls the other.
The only difference is whether you are asking an object about its
class or asking the class directly; other than that #respondsTo:
and #canUnderstand: MEAN THE SAME THING.

In fact, one can argue that #canUnderstand: is dangerously misleading
in precisely the same way as #respondsTo:, and having a
#canHonestlyUnderstand: message which checks for not starting with
"self shouldNotImplement" or "self error: '...'" would be a good idea.

Given the intimate connection between #respondsTo: and #canUnderstand:,
if one is overriding #doesNotUnderstand: and #respondsTo:, shouldn't
#canUnderstand: be overridden too?
	



More information about the Squeak-dev mailing list