Usually when I get to object oriented programming and I ask for characteristics of an OOP language, I get the text book mantra: encapsulation, inheritance and polymorphism – good. And then I ask what is the purpose of each of them.
What happens then used to let me a bit perplexed, but in time, since it happened so many times, I came to just expect it. Instead of getting an explanation of the purpose of inheritance for example, I get and explanation of how it works.
I am not sure how so many people go through so many years of school, which is supposed to make us better at thinking, and they fail to differentiate the “why” and the “how”.
And then I press and make it obvious that I want to hear their opinion about the purpose of inheritance in OOP. And invariably I get this precooked answer (not so nicely expressed): inheritance is the way to achieve code reuse.
No it is not! And I will explain immediately.
But before that I will let you know what this answer and its frequency tell me:
- Schools no longer teach students to think for themselves
- Teachers have little practical experience in the subject they teach
- Not everything that passes as common sense and established knowledge is actually true (this might be an understatement)
- Software crisis starts in school
Then, what is inheritance for?
Inheritance is a mechanism used to achieve categorization and to facilitate polymorphism. Using inheritance you can build a hierarchy of concepts separated in categories at different levels of abstraction. By doing this, you can efficiently use another OOP concept, polymorphism, which allows the same control code to manage all objects in a category even if they are different in their implementation.
This is the main driver for using inheritance in the design of a software system. Not code reuse.
Inheritance, while a very powerful tool, it is very hard to use right. While the rule of thumb – use inheritance for “is a” relationships and composition for “has a” relationships – is very true, applying it in non trivial situations is difficult and wanders close to philosophy. Think about this question: “Is an CircusDog a Dog or maybe CircusDog is just a role a Dog plays?”
This difficulty and ambiguity leads to wrong usage of inheritance more often than not. Because of this inheritance shall be reserved for specific situations where it makes sense. Most of the situations are covered by composition and, for languages that support the concept, by interface implementation.
Incidental code reuse due to inheritance
There is some code reuse associated with inheritance:
- Derived classes can (if desired) reuse code from the super-class hierarchy
- Control code taking advantage of polymorphism is reused for every class in a category
But this is not the reason to use inheritance. The reasons for using inheritance are modularity, separation of concerns, clear representation of concepts, categorization and polymorphism.
How to achieve real code reuse
A better way for achieving code reuse is composition and since there are lots of articles on the subject I am not going to beat the dead horse here.
As a library and framework designer avoid forcing the client code to derive from your classes. It is better to provide self contained pieces of functionality and, if needed and the language you use permits, provide interfaces for extended functionality.
The education factor
Everybody seems to think that we are traversing an ongoing software crisis and nobody knows the solution and the way out. My opinion is the only possible answer is education. What kind of education? The kind that makes you ask yourself “why”. The current education is oriented towards the “how”, and while this is important it is not by far sufficient.
Ideally the schools and later the employers should try to provide this kind of education to students and programmers. But the cruel reality will probably prevent this utopia from coming into reality: lack of experienced and passionate teachers, reluctance of employers at consuming the time of their top talent on mentoring tasks and so on.
So what is the solution? I think the solution is for us to teach ourselves by trying new things, by reading the work of good programmers, by working with them and by keeping all the time the question “why” open in our minds.