Colin Putney wrote:
On Dec 15, 2003, at 2:58 PM, Julian Fitzell wrote:
If you ask me, this is the crux of the argument that the rest of the thread is missing. self subclassResponsibility is not really a meta marker on the class - it's an error. It's implemented as:
I'd go even futher here:
First, the fact is Smalltalk doesn't really have the notion of abstract methods. I don't see this as a short coming of Smalltalk. Abstract
Nor do I
methods are only needed in languages that confuse classes with type, as Peter mentioned earlier. In order to support polymorphism you need to put the method "too high" in the class hierarchy so that the type checker won't complain when it gets sent to the supertype.
Now, a problem that Smalltalk *does* face is that MNU errors are ambiguous. When you get one, the problem might be in either then sender or the receiver. That is, either the message shouldn't have been sent, or the receiver should have understood it. When a programmer calls #subclassResponsibility or #shouldNotImplement, what she's really doing is disambiguating the error.
This is an interesting way of looking at it and a subtlety I hadn't quite put my finger on.
In the case of #subclassResponsibility, she is saying that the message was correct, and the object should respond to it. The fact that it didn't is an error, and the fix is not to avoid sending the message, but to implement the method. The reverse situation applies to #shouldNotImplement. The programmer is telling us that the message makes no sense to this object and should not have been sent. This clarification is especially handy when the limitations of single inheritence (ie, lack of Traits) cause the object inherit an inappropriate method, which, if activated, would result in an error even more obscure than MNU.
I think #shouldNotImplment is misnamed. It should really be #cannotUnderstand. Conversely, #canUnderstand: is asking whether or not it makes sense to send a certain message to an object. So, for the following code, I think it would be reasonable to get a #subclassResponsibility error, but not a #shouldNotImplement error.
(object canUnderstand: #foo) ifTrue: [object foo[]
I agree that #shouldNotImplement is a strange name (I think #shouldNotBeCalled or something would be better since it *has* implemented the method). But, I'm still not sure #canUnderstand: should be looking at the method source to come up with an answer. I understand the desire for a mechanism that works like that, but using method calls as a marker to anything but the human eye seems pretty fishy to me.
The "right" solution, I suppose, is to get rid of the uses of #shouldNotImplement by using Traits (or whatever), since their very presence smells of a hack in the first place. Adding any behaviour to #canUnderstand: to account for this hack is then, by definition I think, also a hack. Which I guess is possibly ok as long as we accept it and comment it as such. But I think it's better to limit the hack to getting an error when you do something wrong (calling a method that should not ideally even be implemented) rather than pushing it into other methods: the hack will still be a hack but it will be harder to isolate.
For example, someone might write:
true ifTrue: [self shouldNotImplement]
or:
false ifTrue: [self shouldNotImplement]
and we couldn't write code that would actually catch both cases properly. Hack, hack, hackety, hack... :)
Julian