Implementation Inheritance Considered Harmful?

Standard

As the years go by and I see more and more painful bugs and convoluted architectures in OOP systems the more convinced I am that implementation inheritance is almost always the wrong answer, and that some kind of trait/mixin/delegation system is superior.

Inheritance sucks partly because you’re expected to extend a class that you didn’t write (or that you at least ostensibly plan to modify independently), by patching into a few of the methods here and there and mucking around with the “protected” innards. This is hardly ever a great long-term design strategy for all but the most carefully designed frameworks (which, in turn, tend to make heavy use of “sealed” classes – i.e. disallowing inheritance!).

I much prefer to put all the “hierarchy” in interfaces, and let the classes themselves be “flat”. That way only you need to worry about the internals of your class, and you don’t have to care about what anyone else might do to them without your knowledge.

But even when inheritance works it’s often not desirable. Consider a simple C# GUI dialogue box that asks the user for his name. What’s the interface to this class that a client needs to cope with? Well, if you write it in idiomatic C# by inheriting from Form, it’ll have over 300 public members! 300! For asking the user what his name is! How many of those members do you actually need to use the form? About two or three, at most, I’d guess. So the problem with just blindly extending another class is that each level in the hierarchy you can only add more and more cruft, never remove, and you probably don’t need most of it for your specific version of the class in question. Wouldn’t it make more sense if more specific classes had more specific interfaces?

I’d prefer to write a simple dialogue box by sticking a Form as a member, and write two or three public methods to do the things that people need to do for this specific class. That keeps it simple and obvious. I’m still reusing the heavy-weight and general Form class, but the users of my new class don’t have to see all that. This works fine until you need to use the new dialogue box polymorphically with some other Form-based class.

Really what you’d want is each class to implement a ton of tiny interfaces for each aspect of its behaviour. Most of the time you’d just implement all the interfaces from scratch. Occasionally though, you really do want to just override some tiny part, and you would do so through delegation, not inheritance. You’d keep the “base class” as a member, implement all the interfaces you care about (ideally a small subset of the “base class” interfaces), but forward some of them directly to the “base”. Clearly a language could benefit from supporting this kind of delegation strategy directly, to avoid tedious typing.

I’d like to see a modern, statically typed, OOP language try this delegation/traits based approach to see how it would work in practice. I suspect it would encourage much better programming patterns (customizable and generic components that get specialized and wrapped up into a clean interface for specific instances, rather than relying on inheritance to override bits here and there of some non-generic base class).

As an aside, functional programming in the guise of e.g. Haskell shows how composition and delegation (while implementing type hierarchy “interfaces”) can work beautifully. But I’m sure OOP could be made to work if we just get rid of this unhealthy obsession with inheritance (which was never really the point of it in the first place).

Advertisements

7 thoughts on “Implementation Inheritance Considered Harmful?

  1. Sutter and Alexandrescu wrote a book “C++ Coding Standards”. They defined good rules on when inheritance must be used: when you need polymorphical behaviour, when you need access to protected functions/members and when you need to pass instances of your new class as a pointer to the base class. In all other cases you should consider aggregation or other more appropriate pattern.

    P.S. take look at D language v2.0 (by Alexandrescu).

    • I’d argue that polymorphism only requires a shared interface (vtable, structural typing, type classes, etc.), not implementation inheritance. I’d also argue that accessing protected members is almost never the right thing to do so it’s no great loss.

      So while they, and others like the Gang of Four, argue for composition as the default strategy, it seems to me that the general attitude in the “real world” is one where inheritance is seen as an important aspect of OOP, rather than something to be used very sparingly and ideally not at all. For that reason I’d like to see an OOP language that eliminated implementation inheritance altogether, and compensated by supporting traits and some convenient facility for delegation. I strongly suspect that it would be a net win.

      I have looked at D 2.0, and it’s really nice. There are some unsatisfactory things with it though. For one thing it’s a bit too “kitchen-sink” for me, and another thing is that they’re still making the “billion dollar mistake” of nullable pointers which is probably the main source of runtime crashes in single-threaded applications in memory-safe languages. And then, of course, like most OOP languages it over-emphasizes inheritance over interfaces and composition.

      • Have you had a look at Clojure (clojure.org)? As of version 1.2 it supports “protocol”s, which is like an interface which can be attached to existing types and implemented there. I am not sure it has build-in delegation functionality, but that could certainly be supported.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s