58

It's been generally accepted in the OO community that one should "favor composition over inheritance". On the other hand, inheritance does provide both polymorphism and a straightforward, terse way of delegating everything to a base class unless explicitly overridden and is therefore extremely convenient and useful. Delegation can often (though not always) be verbose and brittle.

The most obvious and IMHO surest sign of inheritance abuse is violation of the Liskov Substitution Principle. What are some other signs that inheritance is The Wrong Tool for the Job even if it seems convenient?

4
  • 4
    If you don't own the class you're overriding, I would use composition instead, unless it's the normal thing to do, like a UIView in Cocoa. Oct 16, 2010 at 18:11
  • 6
    Is it just me or everyone seems to be over using the term "code smell" in prog.se instead of just saying bad design?
    – Simon
    Mar 19, 2011 at 4:45
  • 10
    @Simon "code smell" is less pejorative than "bad design" and allows scope for the code to be proven valid on review. The concept of "code smell" is to flag a piece of code that warrants investigation to be improved rather than a instant judgement that it is "bad" Ref: codinghorror.com/blog/2006/05/code-smells.html Jan 12, 2012 at 23:56
  • In-her-it-ance A-buse: Academic OOP. Dec 15, 2012 at 6:26

9 Answers 9

53

When inheriting just to get functionality, you're probably abusing inheritance. This leads to the creation of a God Object.

Inheritance itself is not a problem as long as you see a real relation between the classes (like the classic examples, such as Dog extends Animal) and you're not putting methods on the parent class that doesn't make sense on some of it's children (for example, adding a Bark() method in the Animal class wouldn't make any sense in a Fish class that extends Animal).

If a class needs functionality, use composition (perhaps injecting the functionality provider into the constructor?). If a class needs TO BE like other, then use inheritance.

5
  • 12
    This was going to be my answer as well. Use inheritance if A is a B. Use composition if you just want A and B to share some code. Oct 17, 2010 at 2:18
  • 5
    Shouldn't everything inherit from the God Object??
    – mlvljr
    Nov 10, 2010 at 0:07
  • 12
    @mlvljr: If everything inherits from God, then everything has the same capability as God, which is a little ridiculous. Everything should inherit from the Higgs Boson object ;)
    – Matt Ellen
    Apr 4, 2011 at 12:26
  • 7
    I wonder where we put that HiggsBoson class.
    – Spoike
    Oct 5, 2011 at 11:02
  • 6
    HiggsBoson goes in the chucknorris namespace
    – pedorro
    Sep 5, 2014 at 16:54
43

I would say, taking the risk of being shot down, that Inheritance is a code smell in itself :)

The issue with inheritance is that it can be used for two orthogonal purposes:

  • interface (for polymorphism)
  • implementation (for code reuse)

Having a single mechanism to get both is what leads in "inheritance abuse" in the first place, since most people expect inheritance to be about interface, but it might be used to get default implementation even by otherwise careful programmers (it's just so easy to overlook this...)

In fact, modern languages like Haskell or Go, have abandonned inheritance in order to separate both concerns.

Back on track:

A violation of the Liskov Principle is therefore the surest sign, since it means that the "interface" part of the contract is not respected.

However even when the interface is respected, you might have objects inheriting from "fat" base classes just because one of the methods was deemed useful.

Therefore the Liskov Principle in itself is not enough, what you need to know is whether or not the polymorphism is used. If it isn't, then there wasn't much point in inheriting in the first place, that's an abuse.

Summary:

  • enforce the Liskov Principle
  • check it's actually used

A way around it:

Imposing a clear separation of concerns:

  • only inherit from interfaces
  • use composition to delegate implementation

means that at least a couple keystrokes are needed for each method, and suddenly people begin to think about whether or not it's such a great idea to reuse this "fat" class for just a small piece of it.

12
  • 5
    This is reasonable IMHO only if your language allows automagic delegation of everything in a single line of code just like the way inheritance works. If it requires a metric fsckton of boilerplate, then this has to be weighed.
    – dsimcha
    Oct 16, 2010 at 20:50
  • 5
    "Inheritance is code smell." Wow! Inheritance is good, it is the use of it that can be evil.
    – Tim Murphy
    Oct 17, 2010 at 4:28
  • 3
    @dsimcha: actually, it's better if the language does not allow automagic delegation, because forcing the programmer to type somehow forces him to think about whether or not what he's typing is really useful. Oct 17, 2010 at 10:18
  • 5
    @Tim Murphy: I really think that inheritance is a poorly designed mechanism, though it's always easy to say a posteriori. Inheritance violates the "Single Responsability Principle" :) Oct 17, 2010 at 10:19
  • 7
    "Modern languages" always seems to mean "the languages I like best". C# is a modern language, and it certainly hasn't abandoned inheritance. That said, you make some good points. Oct 17, 2010 at 17:05
15

Is it really "generally accepted"? It's an idea I've heard a few times, but it's hardly a universally-recognized principle. As you just pointed out, inheritance and polymorphism are the hallmarks of OOP. Without them, you've just got procedural programming with goofy syntax.

Composition is a tool for building objects a certain way. Inheritance is a tool for building objects a different way. There's nothing wrong with either of them; you just have to know how they both work and when it's appropriate to use each style.

1
  • 4
    its 'universally recognised' by those coders who use languages that don't provide proper inheritance and so force you to use composition :)
    – gbjbaanb
    Jul 21, 2011 at 15:55
5

The strength of inheritance is reusability. Of interface, data, behavior, collaborations. It's a useful pattern from which to convey attributes to new classes.

The drawback to using inheritance is reusability. The interface, data and behavior are encapsulated and transmitted en masse, making it an all-or-nothing proposition. The problems become especially evident as hierarchies become deeper, as properties which might be useful in the abstract become less so and begin to obscure properties at the local level.

Every class that uses the composition object will have to more-or-less re-implement the same code to interact with it. While this duplication requires some violation of DRY, it affords greater freedom for designers to pick-and-choose those properties of a class most meaningful to their domain. This is particularly advantageous when classes become more specialized.

In general, it should be preferred to create classes via composition, and then converting to inheritance those classes with the bulk of their properties in common, leaving the differences as compositions.

IOW, YAGNI (You Aren't Gonna Need Inheritance).

4
  • Could you maybe expand a little on what you mean by "composition will require some violation of DRY" please? Mar 15, 2011 at 17:22
  • @flamingpenguin, I have done so. Mar 18, 2011 at 22:48
  • So when I use inhertiance in C++ via mixins and compose my classes, how is that pick-and-choosing worse than composition (assuming the IS-A relationship applies well)? Also, the problem you are describing in the second paragraph is still present in composition, it's just more obscured because every superclass might have duplicated/unused memebers with methods rather than methods themseleves.
    – MrFox
    Feb 21, 2013 at 16:02
  • 1
    DRY is less important than loosening unnecessary coupling.
    – Zhuinden
    Feb 26, 2020 at 22:24
3

If you are subclassing A to class B but nobody cares if B inherits from A or not, so that's the sign that you might be doing it wrong.

2

"Favor composition over inheritance" is the silliest of assertions. They are both essential elements of OOP. It's like saying "Favor hammers over saws".

Of course inheritance can be abused, any language feature can be abused, conditional statements can be abused.

2
  • 16
    I downvoted you, so let me explain why: I don't think is silly at all. It's a good heuristic, since deciding when to use one or the other is not a clear cut problem with a definite answer. Composition provides several advantages at the cost of obscuring the classes' relationship semantics to the human, which is one of the main points of OOP (code models real world). Thus, advocating for inheritance avoidance is somewhat counter intuitive. In short, if designing is somewhat of an art, and we are in a grey area, using words like "favour" is apt for the matter at hand.
    – DPM
    Dec 10, 2012 at 15:32
  • 2
    +1 this is no longer a heuristic, as we can see plainly in this question. It is now firmly in the category of cargo cult programming. Though having true value originally, the use of the word "favour" no longer carries value and is clearly seen to mean "always". Dec 15, 2012 at 18:28
1

I think battles like inheritance vs. composition, are really just aspects of a deeper core battle.

That fight is: what will result in the least amount of code, for the greatest expandability in future enhancements?

That's why the question is so hard to answer. In one language it could be that inheritance is more quickly put into place than composition than in some other language, or vice-versa.

Or it could be the specific problem you are solving in code benefits more from expedience than a long-term vision of growth. That's as much a business problem as a programming one.

So to get back to the question, inheritance could be wrong if it's putting you into a straight-jacket at some point in the future - or if it's creating code that does not need to be there (classes inheriting from others for no reason, or worse yet base classes that start to have to do a lot of conditional tests for children).

0

Perhaps most obvious is when the inheriting class ends up with a pile of methods/properties that are never used in the exposed interface. In the worst cases, where the base class has abstract members, you'll find empty (or meaningless) implementations of the abstract members just to 'fill in the blanks' as it were.

More subtly, sometimes you see where in an effort to increase code reuse two things which have similar implementations have been squeezed into one implementation - despite those two things not being related. This tends to increase code coupling and disentangling them when it turns out that the similarity was just a coincidence can be quite painful unless it's spotted early.

Updated with a couple of examples: Although not directly to do with programming as such, I think the best example for this sort of thing is with localisation/internationalisation. In English there's one word for "yes". In other languages can be many, many more in order to agree grammatically with the question. Someone could say, ah let's have a string for "yes" and that's fine for lots of languages. Then they realise that the string "yes" doesn't really correspond to "yes" but actually the concept of "the affirmative answer to this question" - the fact that it's "yes" all the time is a coincidence and the time saved only having one "yes" is completely lost in disentangling the resulting mess.

I've seen one particularly nasty example of this in our code base where what was actually a parent -> child relationship where the parent and child had properties with similar names was modelled with inheritance. No-one noticed this as everything seemed to be working, then the behaviour of the child (actually base) and parent (subclass) needed to go in different directions. As luck would have it, this happened at exactly the wrong time when a deadline was looming - in attempting to tweak the model here and there the complexity (both in terms of logic and code duplication) went through the roof immediately. It was also really difficult to reason about/work with as the code simply didn't relate to how the business thought or talked about the concepts these classes represented. In the end we had to bite the bullet and do some major refactoring which could have been completely avoided if the original guy hadn't decided that a couple of similar sounding properties with values that happened to be the same represented the same concept.

3
  • I would adjust that: "are never used in the exposed interface" or something like that. A subclass may use all of its super's methods, but not need to expose any of these. Oct 16, 2010 at 18:09
  • Yep, that's what I meant, I'll amend now.
    – FinnNk
    Oct 16, 2010 at 18:18
  • thanks, looks good. I wonder if you could give an example of the second point? Sure seems like something really hard to spot, but perhaps not...? Just curious here, I've already upvoted your answer which is all I can do :) Oct 16, 2010 at 22:15
0

There are situations when inheritance should be favored over composition, and the distinction is much more clear cut than a matter of style. I'm paraphrasing from Sutter and Alexandrescu's C++ Coding Standards here as my copy is on my bookshelf at work at the moment. Highly recommended reading, by the way.

First of all, inheritance is discouraged when unnecessary because it creates a very intimate, tightly coupled relationship between base and derived classes that can cause headaches down the road for maintenance. It's not just some guy's opinion that the syntax for inheritance makes it harder to read or something.

That being said, inheritance is encouraged when you want the derived class itself to be reused in contexts where the base class is currently being used, without having to modify the code in that context. For example, if you have code that is starting to look like if (type1) type1.foo(); else if (type2) type2.foo();, you probably have a very good case for looking at inheritance.

In summary, if you just want to reuse base class methods, use composition. If you want to use a derived class in code that currently uses a base class, use inheritance.

Not the answer you're looking for? Browse other questions tagged or ask your own question.