Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usage of self subclassResponsibility

I'm new to Pharo and I'm having trouble grasping some concepts, specifically subclassResponsibilty.

I have the following objecttree:

AbstractDictionary
--TreeBasedDictionary (not abstract)
--AbstractArrayDictionary
----SimpleDictionary (not abstract)
----FastDictionary (not abstract)

All 3 implement the operations at:put: and at: (and more). I understood from class today that I can pull up at:put: to the AbstractDictionary with the following implementation:

at: thisKey put: thisValue
"insert new key / value pair"
^self 
    at: thisKey
    put: thisValue
    duplicate: [self error:'duplicate key']

Then I implemented a metod at:put:duplicate: in TreeBasedDictionary and AbstractArrayDictionary (because the implementation is the same for the latter's subclasses). Then, when I call at:put: on an object it won't find it in the instance of either TreeBasedDictionary , SimpleDictionary or FastDictionary but when looking up the tree it finds this method in the superclass (AbstractDictionary). This will then call self with at:put:duplicate: . This method is implemented by the 3 afore mentioned classes, and then the self which is pointing to the instance of the class that made the initial call is sent the message to execute at:put:duplicate:.

Now, AbstractArrayDictionary,SimpleDictionary and FastDictionary all have a method named size. Both classes at the bottom of the inheritence tree implement this method. AbstractArrayDictionary implements this method as follows

size
"dictionary size"
self subclassResponsibility 

Suppose I implemented this method for my TreeBasedDictionary, I suppose I should implement the size method in my AbstractDictionary class as shown above.

My questions: Why do I need to do it like that, and not like this:

size
"dictionary size"
^self size

And if so, do I remove the method from AbstractArrayDictionary and why?

like image 342
Christophe De Troyer Avatar asked Oct 21 '13 21:10

Christophe De Troyer


1 Answers

Ok, look.

First of all if you use

size
  ^ self size

you'll end up in the infinite recursion. You ask size of object and the size method asks size of the object itself and so on.

Now in general about what you should know.

  1. You should avoid duplication, that's why you are moving similar methods to the parent nodes in hierarchy. If you have a same method in all subclasses, move it into the superclass without hesitation.
  2. You can just implement methods where they should work. E.i. not write methods with self subclassResponsibility at all. Objects should respond to messages that they can understand. Can AbstractDictionary put elements in it? No. Then there can be no method.
  3. It's not nice to do things that I've written in #2 part. Because
    • when you browse AbstractDictionary class you get an idea that it should support at:put:duplicate:, but the functionality depends on the implementation (aka subclass).
    • when someone will be implementing another subclass of your dictionary, for example MagicBagDictionary and will forget to implement at:put:duplicate:, then during execution he will be gently reminded that this is a subclass responsibility and the method should be implemented. Otherwise he will get an error "message not understood by MagicBagDictionary".

Concerning the size method again: if you know at some point where you can get the size - do it. For example if AbstractDictionary has instance variable container that will hold all the element and should be able to tell the size of them - you can implement

size
  ^ container size

in the AbstractDictionary. But if you have no idea ho the element will be stored and how to calculate their size at that point, you should use:

size
  "dictionary size"
  self subclassResponsibility

This way AbstractDictionary is saying:

yes, you can get my size, but I have no idea how to calculate it because I'm not complete. But my subclasses should know that, so don't hesitate to ask.

like image 145
Uko Avatar answered Oct 21 '22 15:10

Uko