136

I always read that composition is to be preferred over inheritance. A blog post on unlike kinds, for example, advocates using composition over inheritance, but I can't see how polymorphism is achieved.

But I have a feeling that when people say prefer composition, they really mean prefer a combination of composition and interface implementation. How are you going to get polymorphism without inheritance?

Here is a concrete example where I use inheritance. How would this be changed to use composition, and what would I gain?

Class Shape
{
    string name;
  public:
    void getName();
    virtual void draw()=0;
}

Class Circle: public Shape
{
    void draw(/*draw circle*/);
}
17
  • 67
    No, when people say prefer composition they really mean prefer composition, not never ever ever use inheritance. Your whole question is based on a faulty premise. Use inheritance when it's appropriate. Feb 9, 2012 at 2:59
  • 2
    You might also want to take a look at programmers.stackexchange.com/questions/65179/…
    – vjones
    Feb 9, 2012 at 3:25
  • 2
    I agree with the Bill, I have see using inheritance a common practice in GUI development. Feb 10, 2012 at 7:57
  • 2
    You want to use composition because a square is just the composition of two triangles, in fact I think all shapes other than ellipse are just compositions of triangles. Polymorphism is about contractual obligations and 100% removed from inheritance. When triangle get's a bunch of oddities added to it because somebody wanted to make it capable of generating pyramids, if you inherit from Triangle you're going to get all of that even though you're never going to generate a 3d pyramid from your hexagon. Feb 11, 2013 at 22:28
  • 3
    @BilltheLizard I think a lot of the people who say it really do mean to never ever ever use inheritance, but they're wrong.
    – user253751
    Nov 6, 2015 at 21:25

5 Answers 5

69

Polymorphism does not necessarily imply inheritance. Often inheritance is used as an easy means to implement Polymorphic behaviour, because it is convenient to classify similar behaving objects as having entirely common root structure and behaviour. Think of all those car and dog code examples you've seen over the years.

But what about objects that aren't the same. Modelling a car and a planet would be very different, and yet both might want to implement Move() behaviour.

Actually, you basically answered your own question when you said "But I have a feeling that when people say prefer composition, they really mean prefer a combination of composition and interface implementation.". Common behaviour can be provided through interfaces and a behavioural composite.

As to which is better, the answer is somewhat subjective, and really comes down to how you want your system to work, what makes sense both contextually and architecturally, and how easy it will be to test and maintain.

5
  • 1
    In practice, how often does "Polymorphism via Interface" show up, and is it considered normal (as opposed to being an exploitation of a langues expressiveness). I would wager that polymorphism via inheritance was by careful design, not some consequence of the language (C++) discovered after it's specification.
    – samus
    Mar 6, 2017 at 18:26
  • 3
    Who would call move() on a planet and a car and consider it the same ?! The question here is in what context should they be able to move ? If they both are 2D objects in a simple 2D game, they could inherit the move, if they were objects in a massive data simulation it might not make much sense to let them inherit from the same base and as a consequence you have to use an interface
    – NikkyD
    Mar 7, 2017 at 15:09
  • 3
    @SamusArin It shows up everywhere, and is considered perfectly normal in languages which support interfaces. What do you mean, "an exploitation of a language's expressiveness"? This is what interfaces are there for.
    – Andres F.
    Mar 7, 2017 at 15:10
  • 1
    @AndresF. I just came across "Polymorphism via Interface" in an example while reading through "Object Oriented Analysis and Design with Applications" which demonstrated the Observer pattern. I then realized my answer.
    – samus
    Mar 7, 2017 at 15:32
  • @AndresF. I guess my vision was a bit blinded regarding this because of how I used polymorphism in my last (first) project. I had 5 record types that all derived from the same base. Anyways thanks for the enlightenment.
    – samus
    Mar 7, 2017 at 16:05
98

Preferring composition isn't just about polymorphism. Although that is part of it, and you are right that (at least in nominally typed languages) what people really mean is "prefer a combination of composition and interface implementation." But, the reasons to prefer composition (in many circumstances) are profound.

Polymorphism is about one thing behaving multiple ways. So, generics/templates are a "polymorphic" feature in so far as they allow a single piece of code to vary its behavior with types. In-fact, this type of polymorphism is really the best behaved and is generally referred to as parametric polymorphism because the variation is defined by a parameter.

Many languages provide a form of polymorphism called "overloading" or ad hoc polymorphism where multiple procedures with the same name are defined in an ad hoc manner, and where one is chosen by the language (perhaps the most specific). This is the least well behaved kind of polymorphism, since nothing connects the behavior of the two procedures except developed convention.

A third kind of polymorphism is subtype polymorphism. Here a procedure defined on a given type, can also work on a whole family of "subtypes" of that type. When you implement an interface or extend a class you are generally declaring your intention to create a subtype. True subtypes are governed by Liskov's Substitution Principle, which says that if you can prove something about all objects in a supertype you can prove it about all instances in a subtype. Life gets dangerous though, since in languages like C++ and Java, people generally have unenforced, and often undocumented assumptions about classes which may or may not be true about their subclasses. That is, code is written as if more is provable than it really is, which produces a whole host of issues when you subtype carelessly.

Inheritance is actually independent of polymorphism. Given some thing "T" which has a reference to itself, inheritance happens when you create a new thing "S" from "T" replacing "T"s reference to itself with a reference to "S". That definition is intentionally vague, since inheritance can happen in many situations, but the most common is subclassing an object which has the effect of replacing the this pointer called by virtual functions with the this pointer to the subtype.

Inheritance is a dangerous like all very powerful things inheritance has the power to cause havoc. For example, suppose you override a method when inheriting from some class: all is well and good until some other method of that class assumes the method you inherit to behave a certain way, after all that is how the author of the original class designed it. You can partially protect against this by declaring all methods called by another of your methods private or non-virtual (final), unless they are designed to be overridden. Even this though isn't always good enough. Sometimes you might see something like this (in pseudo Java, hopefully readable to C++ and C# users)

interface UsefulThingsInterface {
    void doThings();
    void doMoreThings();
}

...

class WayOfDoingUsefulThings implements UsefulThingsInterface{
     private foo stuff;
     public final int getStuff();
     void doThings(){
       //modifies stuff, such that ...
       ...
     }
     ...
     void doMoreThings(){
       //ignores stuff
       ...
     }
 }

you think this is lovely, and have your own way of doing "things", but you use inheritance to acquire the ability to do "moreThings",

class MyUsefulThings extends WayOfDoingUsefulThings{
     void doThings {
        //my way
     }
}

And all is well and good. WayOfDoingUsefulThings was designed in such a way that replacing one method doesn't change the semantics of any other... except wait, no it wasn't. It just looks like it was, but doThings changed mutable state that mattered. So, even though it didn't call any override-able functions,

 void dealWithStuff(WayOfDoingUsefulThings bar){
     bar.doThings()
     use(bar.getStuff());
 }

now does something different than expected when you pass it a MyUsefulThings. Whats worse, you might not even know that WayOfDoingUsefulThings made those promises. Maybe dealWithStuff comes from the same library as WayOfDoingUsefulThings and getStuff() isn't even exported by the library (think of friend classes in C++). Worse still, you have defeated the static checks of the language without realizing it: dealWithStuff took a WayOfDoingUsefulThings just to make sure that it would have a getStuff() function that behaved a certain way.

Using composition

class MyUsefulThings implements UsefulThingsInterface{
     private way = new WayOfDoingUsefulThings()
     void doThings() {
        //my way
     }
     void doMoreThings() {
        this.way.doMoreThings();
     }
}

brings back static type safety. In general composition is easier to use and safer than inheritance when implementing subtyping. It also lets you override final methods which means that you should feel free to declare everything final/non-virtual except in interfaces the vast majority of the time.

In a better world languages would automatically insert the boilerplate with a delegation keyword. Most don't, so a downside is bigger classes. Although, you can get your IDE to write the delegating instance for you.

Now, life isn't just about polymorphism. You can don't need to subtype all the time. The goal of polymorphism is generally code reuse but it isn't the only way to achieve that goal. Often time, it makes sense to use composition, without subtype polymorphism, as a way of managing functionality.

Also, behavioral inheritance does have its uses. It is one of the most powerful ideas in computer science. Its just that, most of the time, good OOP applications can be written using only using interface inheritance and compositions. The two principles

  1. Ban inheritance or design for it
  2. Prefer composition

are a good guide for the reasons above, and don't incur any substantial costs.

3
  • 6
    Nice answer. I would summarize it that trying to achieve code reuse with inheritance is plain wrong path. Inheritance is very strong constraint (imho adding "power" is wrong analogy!) and creates strong dependency between inherited classes. Too many dependencies = bad code :) So inheritance (aka "behaves as") typically shines for unified interfaces (=hiding complexity of inherited classes), for anything else think twice or use composition...
    – MaR
    Feb 9, 2012 at 12:39
  • 2
    This is a good answer. +1. At least in my eyes, it does seem though that the extra complication may be a substantial cost, and this has made me personally a little hesitant to make a big deal out of preferring composition. Especially when you're trying to make a lot of unit testing-friendly code through interfaces, composition, and DI (I know this is adding other things in), it seems very easy to make someone go through several different files to look up very few details. Why is this not mentioned more often though, even when only dealing with the composition over inheritance design principle? Mar 7, 2017 at 14:10
  • 1
    I would say inheritance is safe if you're not overriding methods. But composition is still a more flexible solution.
    – jmrah
    Nov 13, 2019 at 3:11
32

The reason people say this is that beginning OOP programmers, fresh out of their polymorphism-through-inheritance lectures, tend to write large classes with lots of polymorphic methods, and then somewhere down the road, they end up with an unmaintainable mess.

A typical example comes from the world of game development. Suppose you have a base class for all your game entities - the player's spaceship, monsters, bullets, etc.; each entity type has its own subclass. The inheritance approach would use a few polymorphic methods, e.g. update_controls(), update_physics(), draw(), etc., and implement them for each subclass. However, this means you're coupling unrelated functionality: it is irrelevant what an object looks like for moving it, and you don't need to know anything about its AI to draw it. The compositional approach instead defines several base classes (or interfaces), e.g. EntityBrain (subclasses implement AI or player input), EntityPhysics (subclasses implement movement physics) and EntityPainter (subclasses take care of drawing), and a non-polymorphic class Entity that holds one instance of each. This way, you can combine any appearance with any physics model and any AI, and since you keep them separate, your code will be much cleaner too. Also, problems such as "I want a monster that looks like the balloon monster in level 1, but behaves like the crazy clown in level 15" go away: you simply take the suitable components and glue them together.

Note that the compositional approach still uses inheritance within each component; although ideally you'd use just interfaces and their implementations here.

"Separation of concerns" is the key phrase here: representing physics, implementing an AI, and drawing an entity, are three concerns, combining them into an entity is a fourth. With the compositional approach, each concern is modelled as one class.

4
  • 1
    This is all good, and advocated in the article linked in the original question. I would love (whenever you get the time) if you could provide a simple example involving all of these entities, while also maintaining polymorphism (in C++). Or point me to a resource. Thanks.
    – MustafaM
    Feb 10, 2012 at 3:01
  • 1
    I know your answer is very old but I did the same exact thing as you mentioned in my game and now going for composition over inheritance approach.
    – Sneh
    Oct 10, 2015 at 20:44
  • "I want a monster that looks like..." how does this make sense ? An interface does not give any implementation, you would have to copy the look and behaviour code one way or the other
    – NikkyD
    Mar 7, 2017 at 15:04
  • 2
    @NikkyD You take MonsterVisuals balloonVisuals and MonsterBehaviour crazyClownBehaviour and instantiate a Monster(balloonVisuals, crazyClownBehaviour), alongside the Monster(balloonVisuals, balloonBehaviour) and Monster(crazyClownVisuals, crazyClownBehaviour) instances that were instantiated on level 1 and level 15
    – Caleth
    Feb 8, 2018 at 12:50
19

You will see this cycle a lot in software development discourse:

  1. Some feature or pattern (let's call it "Pattern X") is discovered to be useful for some particular purpose. Blog posts are written extolling the virtues about Pattern X.

  2. The hype leads some people to think you should use Pattern X whenever possible.

  3. Other people get annoyed to see Pattern X used in contexts where it is not appropriate, and they write blog posts stating that you should not always use Pattern X and that it is harmful in some contexts.

  4. The backlash causes some people to believe Pattern X is always harmful and should never be used.

You will see this hype/backlash cycle happen with almost any feature from GOTO to patterns to SQL to NoSQL and to, yes, inheritance. The antidote is to always consider the context.

Having Circle descend from Shape is exactly how inheritance is supposed to be used in OO languages supporting inheritance.

The rule-of-thumb "prefer composition over inheritance" is really misleading without context. You should prefer inheritance when inheritance is more appropriate, but prefer composition when composition is more appropriate. The sentence is directed towards people at stage 2 in the hype cycle, who think inheritance should be used everywhere. But the cycle has moved on, and today it seems to cause some people to think inheritance is somehow bad in itself.

Think of it like a hammer versus a screwdriver. Should you prefer a screwdriver over a hammer? The question does not make sense. You should use the tool appropriate for the job, and it all depends on what task you need to get done.

13

The example you've given is one where inheritance is the natural choice. I don't think anyone would claim that composition is always a better choice than inheritance -- it's just a guideline that means that it's often better to assemble several relatively simple objects than to create lots of highly specialized objects.

Delegation is one example of a way to use composition instead of inheritance. Delegation lets you modify the behavior of a class without subclassing. Consider a class that provides a network connection, NetStream. It might be natural to subclass NetStream to implement a common network protocol, so you might come up with FTPStream and HTTPStream. But instead of creating a very specific HTTPStream subclass for a single purpose, say, UpdateMyWebServiceHTTPStream, it's often better to use a plain old instance of HTTPStream along with a delegate that knows what to do with the data it receives from that object. One reason it's better is that it avoids a proliferation of classes that have to be maintained but which you'll never be able to reuse. Another reason is that the object that serves as the delegate can also be responsible for other things, such as managing the data received from the web service.

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