Do Not Use Inheritance

(… to extend existing functionality)

Inheritance does not support inheritance

Inheritance serves two distinct purposes:

  • Reusing and extending existing functionality (represented by the parent class).
  • Creating a subtype relationship, allowing instances of the new class to be used wherever instances of the parent could.

With the notable exception of protected members, the first property can be equally obtained with composition, and the ultimate objective of protected members usually implies that inheritance will be used primarily to specify new behavior for the existing interface of the parent class, instead of being used to extend the functionality of the parent class.

The second property can be used anywhere an instance of the parent class exists, by replacing that instance with one from the new class. The only exception to this is… inheritance!

That is, if the classes FirstDerived and SecondDerived both inherit from the class Base, the parent instance of every FirstDerived instance will always be an instance of Base, and cannot be set to be an instance of SecondDerived. By contrast, with composition, it’s possible to use an object provided as a constructor argument, which may be an instance of any class that inherits from Base.

When does this matter?

In a well-written program, never. After all, if a class follows a typical is-a constraint for its inheritance graph, then nobody will ever want to use a Dog as the parent instance of a Cat (even though both inherit from Animal).

When it matters, however, is the situation where the is-a constraint is not respected. A recent example was the Digitalus CMS, written in PHP using the Object system (though I would not go as far as saying that its design is Object-Oriented). That CMS had a base Content class representing the underlying database representation of content, which was effectively a monostate, and inherited two classes, Page and ContentPage, from that base class. I will ignore for a short while the naming issues there (calling Page something which inherits from what is ultimately a page manager, as well as using only two words for three classes) and dive into the real problem : while Page is-a Content (the former being an administration-only manager allowing modification, while the latter is a guest-only manager), ContentPage is a page of content, which is precisely the kind of thing that Content manages. And therefore, even though a page-of-content is not a content-manager (and is never used as such), page-of-content inherits from content-manager.

In fact, ContentPage goes as far as smashing around the Liskov Substitution Principle with a chainsaw and a sledgehammer, by actually removing from its interface most of the functions provided by its Content parent. Why? To get a handful of functions from the parent available in the child.

My objective was to extend the behavior of Content by creating a new class, LocalContent, that would allow different websites to exist together inside the same Digitalus CMS instance (sharing the same administration), and thus needed to perform site-page associations as part of that model.

However, to extend the behavior of Content, one cannot use inheritance : pages of content are only compatible with the original content manager ! Since the extended content manager cannot be used in all situations, one cannot simply change the base class of ContentPage (this would break code where a Content is necessary), which implies either code duplication or heavy refactoring of third party code (and the implicit compatibility loss with future updates of the tool). By contrast, had the original author used composition, the simple solution would have been to create an additional constructor (for instance, through default parameters in the original constructor) allowing the user to specify what instance of Content or one of its subclasses the content page should use.

The chosen solution was to trash the ContentPage implementation, and write my own (functionally equivalent) version of it using LocalContent through composition. So much for extensibility.

Conclusion

Using inheritance to incorporate the behaviour of a class, when there is no clear is-a relationship, prevents you from extending the base class and incorporating those extensions in your own (something which may indeed prove useful, since no is-a relationship would preclude the existence of such extensions). By contrast, composition adds only minimal overhead (in terms of code to be written) and keeps the benefit of inheritance-based polymorphism for the class you’re writing.

0 Responses to “Do Not Use Inheritance”


  1. No Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



1150 feed subscribers
(readers who polled a feed this week)