We all know that inheritance is bad and that composition over inheritance is a good idea, but do we really understand why? In
most all articles I've found addressing this subject, authors have said that inheritance may be harmful to your code, so it's better not to use it. This "better" part is what bothers me; does it mean that sometimes inheritance makes sense? I interviewed David West (the author of Object Thinking, my favorite book about OOP) a few weeks ago, and he said that inheritance should not exist in object-oriented programming at all (full video). Maybe Dr. West is right and we should totally forget
extends keyword in Java, for example.
I think we should. And I think I know the reason why.
It's not because we introduce unnecessary coupling, as Allen Holub said in his Why extends is evil article. He was definitely right, but I believe it's not the root cause of the problem.
"Inherit", as an English verb, has a number of meanings. This one is what inheritance inventors in Simula had in mind, I guess: "Derive (a quality, characteristic, or predisposition) genetically from one's parents or ancestors".
Deriving a characteristic from another object is a great idea, and it's called subtyping. It perfectly fits into OOP and actually enables polymorphism: An object of class
Article inherits all characteristics of objects in class
Manuscript and adds its own. For example, it inherits an ability to print itself and adds an ability to submit itself to a conference:
This is subtyping, and it's a perfect technique; whenever a manuscript is required, we can provide an article and nobody will notice anything, because type
Article is a subtype of type
Manuscript (Liskov substitution principle).
But what does copying methods and attributes from a parent class to a child one have to do with "deriving characteristics"? Implementation inheritance is exactly that—copying—and it has nothing to do with the meaning of the word "inherit" I quoted above.
Implementation inheritance is much closer to a different meaning: "Receive (money, property, or a title) as an heir at the death of the previous holder". Who is dead, you ask? An object is dead if it allows other objects to inherit its encapsulated code and data. This is implementation inheritance:
Article copies method
print() and attribute
body from class
Manuscript, as if it's not a living organism, but rather a dead one from which we can inherit its parts, "money, properties, or a title."
Implementation inheritance was created as a mechanism for code reuse, and it doesn't fit into OOP at all. Yes, it may look convenient in the beginning, but it is absolutely wrong in terms of object thinking. Just like getters and setters, implementation inheritance turns objects into containers with data and procedures. Of course, it's convenient to copy some of those data and procedures to a new object in order to avoid code duplication. But this is not what objects are about. They are not dead; they are alive!
Don't kill them with inheritance :)
Thus, I think inheritance is bad because it is a procedural technique for code reuse. It comes as no surprise that it introduces all the problems people have been talking about for years. Because it is procedural! That's why it doesn't fit into object-oriented programming.