QR code

Inheritance Is a Procedural Technique for Code Reuse

  • Palo Alto, CA
  • comments

OOPoop

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?

Death at a Funeral (2007) by Frank Oz
Death at a Funeral (2007) by Frank Oz

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:

interface Manuscript {
  void print(Console console);
}
interface Article extends Manuscript {
  void submit(Conference cnf);
}

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:

class Manuscript {
  protected String body;
  void print(Console console) {
    console.println(this.body);
  }
}
class Article extends Manuscript {
  void submit(Conference cnf) {
    cnf.send(this.body);
  }
}

Class 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.”

badge

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.

By the way, we discussed this problem in our Gitter chat (it’s dead already) a week ago, and that’s when it became obvious to me what exactly is wrong with inheritance. Take a look at our discussion there.

sixnines availability badge   GitHub stars