Is Inheritance overrated ? Needed even?


To give some context to this topic, the idea was brought forward to me by Alex Eagle. I was happily coding away when Alex sprung his idea for Composition over Inheritance for Noop – a language we are developing with testability and dependency injection in mind. My gut reaction was that this was blasphemy, and it couldn’t be done. You can’t just do away with inheritance, its one of the building blocks of OO based programming languages. But now, after I have let the idea digest for a few days, it doesn’t seem so far fetched any more. And here’s why.

Let me first talk about the biggest problems with vanilla inheritance as we have it in Java. Joshua Bloch hits it on the nail in his Effective Java book item about “Favoring composition over inheritance.” But lets do a quick recap anyway.

The biggest problem is that inheritance often ends up breaking encapsulation. This is because the child class depends on the implementation of the parent class. But between releases, something in the parent class implementation can change and can break all child classes without even touching its code. Another common gotcha is in how protected fields and members are used. Often, the parent class changes the value of fields depending on how methods are called. Not understanding this behavior often leads to buggy or simply wrong behavior from the subclasses.

Another problem with a subclass – especially from the point of view of unit testing – is that there is no way to create an instance of the subclass in isolation. By this, I mean that everytime I create an instance of the subclass, I am forced to have the parent class as well. In most cases, this shouldn’t be a problem, but I have run into situations where the parent class is just a landmine waiting to explode, with the default constructor not being explicit in stating its dependencies. So instant Kablaam!!! Or the parent class will load things you don’t really care about and make things slow in a test. There was this insidious test I ran into once, which extended a base test case, which did the same thing. About 7 layers deep. And the test itself didn’t really care about 3 or 4 of those layers, but had to jump through all the hoops and get everything because it was a parent class.

There are a few more issues, which are well documented in Effective Java item 16, “Favor composition over inheritance.”. I won’t bore you further on this, assuming I have convinced the skeptics about the problems with inheritance. If not, go read that book, and you shall be convinced. But then, I wanted to postulate on whether it was at all possible to have a programming language which does away with inheritance (As Noop proposes).

So when do we use inheritance ? To me, Polymorphism is about the only time when inheritance and subclassing is deemed appropriate. Be it having different subtypes or just plain old code reuse. So unless you want to have a base abstract class which has some methods defined (Like Shape with draw() method and Circles and Rectangles), inheritance is not really needed.

In Java, interfaces allow you to perform polymorphic operations with abandon, and convert between types. And interfaces don’t straddle you down with the requirement that you get the base class for every instance.

Also, if you use composition, then you can reuse code by using delegation. For example, you could define a Shape interface with a DefaultShape implementation. Now rather than subclassing a concrete type Shape, you could have a Rectangle which implements Shape. And if you wanted to reuse some code, let Rectangle take in a DefaultShape instance and just delegate to it when necessary. This offers multiple benefits. One, you are not tied down to getting things from the base class. In your test, you could pass in a mock, a null, whatever you want. The only problem is that this option is not viable if you don’t have an interface. If that is the case (or the thing you are subclassing is in a package outside of your control), then you are stuck doing inheritance the old fashioned way.

And this is (atleast the last time I heard the proposal) what Noop aims to solve. When you want to subclass, you tell the class what you want to compose. Regardless of whether it is an interface or not, it will create that class with an instance of your composition type. By default, all methods in the composition type will be available in the subclass, and it will delegate automatically, unless you override it. You get complete control over object creation, and this could potentially support multiple inheritance through this approach.

What do other people think ? It this feasible ? Am I missing something obvious when inheritance is the only approach and composition just doesn’t cut it (both right now and in the Noop proposal) ? Are you interested in Noop ? Drop me a line.

, , , , ,

  1. #1 by Chris Allen on August 20th, 2009

    I think it’s a good idea in principal. I’ve always favored composition over inheritance for all the reasons you mentioned, and would like to basically remove the ability to have our developers even do inheritance except for very unique cases. The only time I think it’s truly useful is when using an Abstract class. The whole idea of having to delegate to objects within your code for things you want to all other classes like it to do seems a bit kludgey. But, hey, like you said above, there is a way around it. And yeah, maybe it’s better. But abstract classes are convenient and not that bad as long as you don’t make the inheritance chain any longer than one level.

    So, is it feasible? Yes. Would you be making some things harder, probably. Anyway, this is the first I’ve heard of Noop, I will have to check it out. And thanks for the interesting post.

  2. #2 by Troy Gilbert on August 20th, 2009

    You’re absolutely right, inheritance is most definitely used incorrectly more often than not because of its convenience syntactically, and this is a huge problem overlooked (or left unaddressed) by many language designers (particularly those in the curly-brace lineage).

    The “ideal” object-oriented design has objects speaking to each other only through known interfaces (with the generic “send message” method being an assumed universal amongst all objects). It’s the whole “programming by contract” argument.

    Unfortunately, the C++ designers (or whomever they were borrowing it from) were very implementation-focused and gave us *inheritance*. It worked well (i.e. computationally efficient) to have a “base class”, etc. But a better solution would be to have only interfaces (contracts).

    With the curly-brace languages, you can certainly practice a pure-interface approach with your own class libraries. The pain and suffering is in shared implementations. A huge percentage of the time when you have sub-types you want to suck in the implementation for part of an interface that’s common with the parent type. Inheritance does this (and implies an interface), but it’s a sledgehammer.

    If curly-brace languages had the native notion of *composition*, not just containment, we’d be in business. I can’t remember which language I was working in at the time, but I seriously pushed hard on introducing composition syntax:

    1
    2
    3
    4
    5
    class MyObject implements IReadWriteXml
    {
      private var _xmlParser:XmlParser;
      interface IReadWriteXml to _xmlParser;
    }

    The above should be pretty obvious, with the suggested line translating to “forward all method calls on MyObject that are defined by the IReadWriteXml interface to _xmlParser.” Instead, we have to do this:

    1
    2
    3
    4
    5
    6
    class MyObject implements IReadWriteXml
    {
      private var _xmlParser:XmlParser;
      public function readXml(xml:XML):void { _xmlParser.readXml(xml); }
      public function writeXml():XML { return _xmlParser.writeXml(); }
    }

    And that’s just a trivial example. This is exactly the kind of boiler plate code that higher level languages are supposed to eliminate.

    Multiple prototypes (instead of classes) is another solution, though less precise because it wouldn’t specify which interfaces should be forwarded to which prototype objects. And I don’t know if any languages are multi-prototype.

    As you can see, I’ve been thinking about this language nuisance for damn near a decade, and I know I’m not the only one. Almost every good, data-driven system I’ve code has this very feature, even if only implicitly. Composition is king (for all the reasons you stated) — inheritance is a crutch, a necessary evil, not because it solves problems at the computer science level, but because it solves problems at the implementation level, and only because of the constraints our tools invented and enforce!

  3. #3 by John Lindal on September 23rd, 2009

    To Troy’s point, I ended up doing exactly this when I implemented Erlang Actors in Java. In order to make the threading model configurable at run time (rather than having to inherit from a base class which implemented a particular threading model), I had to delegate the hard way. Luckily, the number of methods was quite small.

    If I remember correctly, Objective C has delegation built in. You can say, If you don’t find the requested method in me, try this other object.

  4. #4 by Tim on October 1st, 2009

    Hi,

    You really should check out functional programming languages based on your comment on favoring composition over inheritance. (besides that, it is ideal for both very large and very small scale programs, and everything in between) Modern functional languages, such as Haskell have very sophisticated ways of dealing with polymorphic types, and good module systems, and make composition very central to coding practice. In Haskell’s case, they separate I/O from functions (by using the I/O Monad), which ensures that function composition remains pure in every case. If you just want some mix of higher order functions and mixed OO techniques, Scala is complex, but might suit your needs. (plus, it’s on the JVM if you’re a java programmer)

(will not be published)