155

In the last few months, the mantra "favor composition over inheritance" seems to have sprung up out of nowhere and become almost some sort of meme within the programming community. And every time I see it, I'm a little bit mystified. It's like someone said "favor drills over hammers." In my experience, composition and inheritance are two different tools with different use cases, and treating them as if they were interchangeable and one was inherently superior to the other makes no sense.

Also, I never see a real explanation for why inheritance is bad and composition is good, which just makes me more suspicious. Is it supposed to just be accepted on faith? Liskov substitution and polymorphism have well-known, clear-cut benefits, and IMO comprise the entire point of using object-oriented programming, and no one ever explains why they should be discarded in favor of composition.

Does anyone know where this concept comes from, and what the rationale behind it is?

Mason Wheeler
  • 82,151
  • 24
  • 234
  • 309
  • 51
    As others have pointed out, it's been around a long time - I'm surprised you're just now hearing of it. It's intuitive to anyone who has been building big systems in languages like Java for any amount of time. It's core to any interview I ever give and when a candidate starts talking about inheritance, I begin to doubt their skill level and amount of experience. Here's a good introduction to why inheritance is a brittle solution (there are many many others): http://www.artima.com/lejava/articles/designprinciples4.html – Janx Apr 04 '11 at 23:59
  • 6
    @Janx: Maybe that's it. I don't build big systems in languages like Java; I build them in Delphi, and without Liskov substitution and polymorphism we'd never get anything done. Its object model is different in certain ways than Java's or C++'s, and a lot of the problems that this maxim seems to be meant to solve don't really exist, or are much less problematic, in Delphi. Different perspectives from different points of view, I guess. – Mason Wheeler Apr 05 '11 at 00:13
  • 1
    There you go. My Delphi experience is exactly zero, so I can't speak to that. But the first few "big things" I ever built in Java relied heavily on inheritance and i paid for it later - much harder to adapt later on. – Janx Apr 05 '11 at 01:20
  • 14
    I spent several years on a team building relatively large systems in Delphi and tall inheritance trees certainly bit our team and caused us significant pain. I suspect that your attention to the SOLID principles is helping you to avoid the problem areass, not your use of Delphi. – Bevan Apr 05 '11 at 08:33
  • 9
    Last few months?!? – Jas Apr 05 '11 at 12:41
  • 7
    IMHO that concept has never been fully adjusted to the variety of languages that support both interface inheritance (i.e., subtyping with pure interfaces) and implementation inheritance. Too many people follow this mantra and don't use enough interfaces. – Uri Apr 05 '11 at 15:04
  • 4
    Keep in mind that the saying is *"favor composition over inheritance"* and not *"inheritance is bad"*. Obviously it is annoying that people parrot the saying over and over but it truly is good advice for producing highly robust and maintainable systems regardless of the language. – ChaosPandion May 26 '11 at 16:10
  • It is difficult to have "Rules" specifically in S/w Designing perf engineering fields. It all depends on answer of "Context of usage" and "It Depends". Composition is definitely should be obvious choice, GOF himself used interface inheritnace through out his Design patterns, and sometimes Abstract classes helps. – Anand Sep 14 '12 at 06:34
  • IMHO It's because a bunch of mainstream languages don't support multiple inheritance and this drives certain design patterns where composition is the only way to do things. – MrFox Nov 26 '12 at 19:43
  • 3
    This may be a good time to point out an interesting human trait--when you first become aware of something's meaning you often hear it repeatedly for a while. It's not that it wasn't there before, it's just that it wasn't significant to you or you weren't looking for instances of it (Like you might have overlooked it in a web search)... Eventually it fades into the background again. Just human nature--there should be a manual for being human that mentions quirks like this (such as the fact that if you are the last of your friends to see a movie you won't like it as much) but there isn't. – Bill K Nov 28 '12 at 18:10
  • It's pretty old, i seem to recall it in a c++ book in the mid nineties. Related question: http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance – Ray Tayek Apr 14 '13 at 03:38
  • 1
    To have more clarity on Why composition should be favored over inheritance, Please read http://efectivejava.blogspot.in/2013/07/item-16-favor-composition-ovr.html –  Jul 29 '13 at 04:55
  • 2
    @Bevan That's why the statement mentions 'composition'. By relying on interfaces, objects can be polymorphic but without the complex parent/child dependency hierarchy. The greatest flaw of inheritance is that it creates dependencies across internal implementations. Fragile/brittle code is code that can't be changed without breaking other code. – Evan Plaice Feb 19 '14 at 00:47
  • There are literally no use cases for which inheritance works and composition doesn't work. The use cases for inheritance are a tiny, strict subset of composition use cases, and they're extremely hard to identify correctly (so inheritance gets shoehorned into lots of other problems). – weberc2 Dec 15 '15 at 15:58

15 Answers15

153

Though I think I've heard composition-vs-inheritance discussions long before GoF, I can't put my finger on a specific source. Might have been Booch anyway.

<rant>

Ah but like many mantras, this one has degenerated along typical lines:

  1. it is introduced with a detailed explanation and argument by a well-respected source who coins the catch-phrase as a reminder of the original complex discussion
  2. it is shared with a knowing part-of-the-club wink by a few in-the-know for a while, generally when commenting on n00b mistakes
  3. soon it is repeated mindlessly by thousands upon thousands who never read the explanation, but love using it as an excuse not to think, and as a cheap and easy way to feel superior to others
  4. eventually, no amount of reasonable debunking can stem the "meme" tide - and the paradigm degenerates into religion and dogma.

The meme, originally intended to lead n00bs to enlightenment, is now used as a club to bludgeon them unconscious.

Composition and inheritance are very different things, and should not be confused with each other. While it is true that composition can be used to simulate inheritance with a lot of extra work, this does not make inheritance a second-class citizen, nor does it make composition the favorite son. The fact that many n00bs try to use inheritance as a shortcut does not invalidate the mechanism, and almost all n00bs learn from the mistake and thereby improve.

Please THINK about your designs, and stop spouting slogans.

</rant>

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Steven A. Lowe
  • 33,808
  • 2
  • 84
  • 151
  • 18
    Booch argues that implementation inheritance introduces high coupling among classes. On the other hand, he considers inheritance the key concept that distinguishes OOP from procedural programming. – Nemanja Trifunovic Apr 05 '11 at 02:06
  • 18
    There should be a word for this kind of thing. *Premature Regurgitation*, maybe? – Jörg W Mittag Apr 05 '11 at 02:08
  • 9
    @Jörg: You know what will happened to a term like Premature Regurgitation? Exactly what is explained above. :) (Btw. when is regurgitation ever not premature?) – Bjarke Freund-Hansen Apr 05 '11 at 13:18
  • 7
    @Nemanja: Right. The question is whether this coupling is really bad. If the classes are conceptually strongly coupled and conceptually form a supertype-subtype relationship, and could never be conceuptually decoupled even if they're formally decoupled at the language level, then strong coupling is fine. – dsimcha Apr 06 '11 at 15:44
  • 5
    The mantra is simple, "just because you can shape play-doh to look like anything doesn't mean that you should make everything out of play-doh." ;) – Evan Plaice Apr 19 '12 at 03:56
  • 3
    @bjarkef Regurgitation is inevitable when you drink too much kool-aid. Touche... – Evan Plaice Apr 19 '12 at 04:08
  • 1
    perhaps the best thing about mindlessly applying this adage in all cases is the wonderful way it can transform C# into VB5 ;) – Steven A. Lowe Jul 31 '12 at 06:33
  • 4
    I don't really have a problem with sayings like this. They are good guidence for n00bs who I'd rather error on the side of blind obeyence until they actually understand the meaning of the word "Prefer" and make better choices. Avoiding highly interlinked models while you are figuring out some best practices is actually quite valuable (at least it is to me if I ever have to deal with your code). – Bill K Nov 28 '12 at 18:23
  • I have no problem "imposing" rigid regurgitative rules on newborn software engineer.. that is.. until they start asking why and challenge me on them. This tells me they are learning and will eventually be able to think for themselves. For the ones who will take it face value maybe they will never learn. So they will make messes but with a set of guidelines the mess will tend to follow a predictable pattern making it easier for me to recover their code... my 2 cent – Newtopian Apr 20 '13 at 19:28
  • 2
    -1 Why does Java's Stack implementation inherit from Vector? Because somebody used inheritance when an interface would have been more appropriate. Now that people depend on Stack and its expected functionality including the parts inherited from Vector. The problem with inheritance is that it bleeds implementation details across functional boundaries when it isn't applied correctly. Worse yet, a lot of eager comp sci grads came out of school with a shiny inheritance hammer looking for nails to pound. – Evan Plaice Feb 19 '14 at 00:57
  • 2
    @EvanPlaice: I didn't write Java's Stack implementation, nor do I think that a Stack is a kind of Vector. In no way do I promote or would I condone such an _inappropriate_ use of inheritance. This is a good example of a developer that did not take the time to think about the design - and thinking is highly recommended. – Steven A. Lowe Feb 24 '14 at 03:53
  • 1
    Let's stick with 'meme' instead of calling this a 'mantra', as it is sad to see this beautiful word, which means the opposite of how you've used it here, misused like this. And sure, I agree that we need to "think", so this answer could apply to literally any "this or that" question out there, that is our nature as human beings. Trudeau had a great comic out there some years back, how thoughts bypassed the mind, and went directly to our mouths, and that is exactly what is happening here. Bottom line, meme, especially in the Snowcrash sense, is much better choice than misusing mantra. – michaelok Nov 12 '15 at 23:30
  • @michaelok: mantra, definition #2 "a statement or slogan repeated frequently" - though 'meme' is appropriate as well. – Steven A. Lowe Nov 14 '15 at 00:01
  • 1
    +1000 if I could, for this: _"soon it is repeated mindlessly by thousands upon thousands who never read the explanation, but love using it as an excuse not to think, and as a cheap and easy way to feel superior to others eventually, no amount of reasonable debunking can stem the "meme" tide - and the paradigm degenerates into religion and dogma."_ – MikeSchinkel May 18 '17 at 22:07
  • This answer uses has very hard English, with no purpose. The very same ideas could be expressed with more understandable sentences and words too. Although English is not my first language, I read English text fluidly, for example 1000s of stackoverflow answers and GOF DP etc. I am sure that even a reader who has English as her/his first language must invest (and waste) more effort to get the point. – g.pickardou Jul 16 '17 at 05:45
  • -1000 If I could. I can only assume you've never had the pleasure of working with the type of code that led to this saying. Erring on the side of composition will never lead to thoughts like "OMG this is the worst code I've ever seen what was this person thinking! It will be faster to rewrite this whole mess than try to fix it!" Never. Composition absolutely cannot be abused the way that inheritance can, and the truth is that it is absolutely a better solution most of the time. I wrote VB for years and I will take that over bad OO code *any day*.. – BVernon Jan 24 '18 at 08:41
  • 2
    @BVernon I've seen a ton of terrible code in my career - I even wrote some of it. But I don't blame the tools for their misuse. – Steven A. Lowe Feb 03 '18 at 01:54
  • @StevenA.Lowe Not sure what you mean by that... I don't either? When I used to have to work in VB6 I always though it would make my life so much easier if it only allowed inheritance. A more experienced programmer mentioned to me though that of all the features to not have, it really wasn't 'that' big of deal for VB6 not to have inheritance and I've since come to agree. You can use composition for virtually anything you could do with inheritance and still write good code. The opposite is not true. – BVernon Feb 04 '18 at 04:06
  • 1
    @BVernon: anything...except inheritance. – Steven A. Lowe Feb 28 '18 at 09:10
  • 1
    @BVernon Your assumptions would be incorrect, at least with me. Erroring on the side of composition _(in languages that required interfaces to be explicitly implemented)_ results in highly fragile code that cannot hold up over time as requirements change (see https://twitter.com/davecheney/status/997784227667103747) as named* implemented interfaces are **never** allowed to **evolve** backward-compatibly. That is FAR worse than the problems creating by the fragile-base-class problem. To be clear, both are problems. But you don't fix the problem of a hot frying pan by jumping into a fire. – MikeSchinkel May 10 '19 at 21:32
  • @MikeSchinkel Not sure if you've got the right tweet? I went to read it but it just says "Software engineering is what happens to programming when you add time, and other programmers." – BVernon May 12 '19 at 07:45
  • @MikeSchinkel We're not quite on the same page here though. The issue you're describing is with interfaces; not necessarily composition. Composition doesn't require interfaces. For example: Say a base Car class has wheel properties like diameter, and methods to move the wheel. But what happens when I've got an airplane or a boat? It would've been better to create a Wheel class to hold the data/behavior. I can put an instance of it on the base Car, AND I can use it for other types of vehicles. That's composition over inheritance, and it has nothing to do with interfaces. – BVernon May 12 '19 at 08:01
  • @MikeSchinkel Interfaces do not exist for the sake of composition. When they are used to serve their proper purpose then the downsides you mention are a moot point because the alternative of not using them would be totally unreasonable. (https://stackoverflow.com/questions/1686174/when-should-one-use-interfaces) – BVernon May 12 '19 at 08:05
  • Everything about this post makes me happy :) Particularly the tags – Shane Jul 01 '22 at 00:32
80

Experience.

Like you say they are tools for different jobs, but the phrase came about because people were not using it in that way.

Inheritance is primarily a polymorphic tool, but some people, much to their later peril, attempt to use it as a way of reusing/sharing code. The rationale being "well if I inherit then I get all the methods for free", but ignoring the fact that these two classes potentially have no polymorphic relationship.

So why favour composition over inheritance - well simply because more often than not the relationship between classes is not a polymorphic one. It exists simply to help remind people to not knee jerk respond by inheriting.

Stephen Bailey
  • 2,236
  • 14
  • 14
  • 7
    So basically, you can't say "you shouldn't be using OOP in the first place if you don't understand Liskov substitution," so you say "favor composition over inheritance" instead as an attempt to limit the damage done by incompetent coders? – Mason Wheeler Apr 04 '11 at 23:08
  • 15
    @Mason: Like any mantra, "favor composition over inheritance" is targeted at beginner programmers. If you already know when to use inheritance and when to use composition then it's pointless to repeat a mantra like that. – Dean Harding Apr 04 '11 at 23:14
  • @Dean: Fair enough. But I've seen it so much lately, used in such a wide set of contexts, that you could almost mentally replace the phrase with "inheritance considered harmful." It's that attitude that I find a little bit ridiculous. – Mason Wheeler Apr 04 '11 at 23:16
  • 7
    @Dean - I'm not sure *beginner* is the same as one who doesn't understand inheritance best practices. I think there is more to it than that. Poor inheritance is the cause of many, many headaches in my job and it's not code written by programmers who would be considered "beginners". – Nicole Apr 04 '11 at 23:27
  • 1
    @Renesis: true enough! – Dean Harding Apr 04 '11 at 23:35
  • 7
    @Renesis: First thing I think of when I hear that is, "some people have ten years of experience, and some people have one year of experience repeated ten times." – Mason Wheeler Apr 04 '11 at 23:46
  • 1
    @Mason: I love this sentence! – Matthieu M. Apr 06 '11 at 17:04
  • @Mason Generally speaking, you have a greater chance of falling in that "pit of success" when you use composition. The classic example is that developers tend to abuse inheritance by inheriting from a class that has methods that another class wants but they are completely unrelated classes. If that code to be reused was abstracted out into it's own class, it doesn't break cohesion nor does it look strange for the subclass to have methods that don't belong to it but inherited anyway. – Korbin Aug 18 '11 at 15:01
  • 9
    I was designing a fairly large project right after first "Getting" OO and relied on it heavily. Although it worked well, I constantly found the design brittle--causing minor irritations here and there and sometimes making certain refactors a complete bitch. It's kind of difficult to explain the whole experience, but the phrase "Favor Compisition over Inheritence" describes it EXACTLY. Note that it does not say or even imply "Avoid Inheritence", it simply gives you a little nudge when the choice is not obvious. – Bill K Nov 28 '12 at 18:04
  • 1
    @MasonWheeler The problem with inheritance is that it bleeds implementation-specific details across class boundaries. Most people are mistakenly taught in school to use inheritance for polymorphism. Interfaces work just as well and support multiple inheritance. Composition here simply means, design a consistent API and enforce it via interface contracts. Inherit only where it makes sense. – Evan Plaice Feb 19 '14 at 01:09
  • Inheritance isn't even very useful for polymorphism. What if you want to pass two different things with a similar interface? A ByteArrayStream and a FileStream share zero implementation details, but have a very similar interface. – weberc2 Dec 12 '15 at 04:01
  • @weberc2 Polymorphism is exactly what you're describing there-- inherit to implement (not to reuse). They would both inherit from a common Stream interface/abstract class. – Rob K Jun 22 '16 at 19:38
  • @RobK implementing an interface is different than inheriting an implementation. If you want polymorphism, think interfaces. Perhaps the only time you should use inheritance is when late binding is necessary, and I say "perhaps" because I haven't explored the alternatives very thoroughly yet. – weberc2 Jun 22 '16 at 19:43
  • The Wikipedia article on composition over inheritance provides a pretty good idea of when to use composition and when to use inheritance. For example, a duck is something that can fly, but so is an airplane. You might define a Flyable interface that classes Duck and Airplane implement. Then you can create Duck subclasses like Mallard duck or RedheadDuck. You can create Airplane subclasses like Boeing737. – moonman239 Sep 16 '21 at 15:50
46

It's not a new idea, I believe it was actually introduced in the GoF design patterns book, which was published in 1994.

The main problem with inheritance is that it's white-box. By definition, you need to know the implementation details of the class you're inheriting from. With composition, on the other hand, you only care about the public interface of the class you're composing.

From the GoF book:

Inheritance exposes a subclass to details of its parent's implementation, it's often said that 'inheritance breaks encapsulation'

The wikipedia article on the GoF book has a decent introduction.

Dean Harding
  • 19,871
  • 3
  • 51
  • 70
  • 14
    I don't agree with that. You don't need to know the implementation details of the class you're inheriting from; only the **public** and **protected** members exposed by the class. If you have to know the implementation details, then either you or whoever wrote the base class is doing something wrong, and if the flaw is in the base class, composition won't help you fix/work around it. – Mason Wheeler Apr 04 '11 at 23:15
  • 20
    How can you disagree with something you haven't read? There's a solid page and a half of discussion from GoF that you are getting just a tiny view of. – philosodad Apr 04 '11 at 23:30
  • 7
    @pholosodad: I'm not disagreeing with something I haven't read. I'm disagreeing with what Dean wrote, that "By definition, you need to know the implementation details of the class you're inheriting from," which I have read. – Mason Wheeler Apr 04 '11 at 23:47
  • 11
    What I wrote is just a summary of what's described in the GoF book. I might've worded it a little strongly (you don't need to know *all* the implementation details) but that's the general reason why the GoF says to favour composition over inheritance. – Dean Harding Apr 05 '11 at 00:05
  • 2
    Correct me if I'm wrong but I see it as, "favor explicit class relationships (ie Interfaces) over implicit (ie inheritance)." The former tell you what you need without telling you how to do it. The latter not only tell you how to do it but will make you regret it down the road. – Evan Plaice Apr 19 '12 at 04:03
  • I very like this one: simple readable clear. – NingW Apr 02 '19 at 16:29
29

"Composition over inheritance" is a short (and apparently misleading) way of saying "When feeling that the data (or behaviour) of a class should be incorporated into another class, always consider using composition before blindly applying inheritance".

Why is this true ? Because inheritance creates tight, compile-time coupling between the 2 classes. Composition in contrast is loose coupling, wich among others enables clear separation of concerns, the possibility of switching dependencies at runtime and easier, more isolated dependency testability.

That only means inheritance should be handled with care because it comes at a cost, not that it isn't useful. Actually, "Composition over inheritance" often ends up being "Composition + inheritance over inheritance" since you often want your composed dependency to be an abstract superclass rather than the concrete subclass itself. It allows you to switch between different concrete implementations of your dependency at runtime.

For that reason (among others), you'll probably see inheritance used more often in the form of interface implementation or abstract classes than vanilla inheritance.

A (metaphorical) example could be :

"I have a Snake class and I want to include as part of that class what happens when the Snake bites. I would be tempted to have the Snake inherit a BiterAnimal class that has the Bite() method and override that method to reflect venomous bite. But Composition over Inheritance warns me that I should try to use composition instead... In my case, this could translate into the Snake having a Bite member. Bite class could be abstract (or an interface) with several subclasses. This would allow me nice things like having VenomousBite and DryBite subclasses and being able to change bite on the same Snake instance as the snake grows of age. Plus handling all the effects of a Bite in its own separate class could allow me to reuse it in that Frost class, because frost bites but isn't a BiterAnimal, and so on..."

guillaume31
  • 8,358
  • 22
  • 33
  • 4
    Very good example with the Snake. I met a similar case recently with my own classes – Maksee Apr 19 '12 at 06:59
  • 1
    Appreciate the Snake ;) But following your *"Composition + inheritance over inheritance"* observation, `Snake` should also **be** a `BiterAnimal` so that it can express polymorphic behavior when part of `biterAnimals` collections. – lcfd Dec 15 '22 at 07:22
28

To answer part of your question, I believe this concept first appeared in the GOF Design Patterns: Elements of Reusable Object-Oriented Software book, which was first published in 1994. The phrase appears at the top of page 20, in the introduction:

Favor object composition over inheritance

They preface this statement with a brief comparison of inheritance with composition. They don't say "never use inheritance".

vjones
  • 908
  • 7
  • 11
22

Some possible arguments for composition:

Composition is slightly more language / framework agnostic
Inheritance and what it enforces / requires / enables will differ between languages in terms of what the sub/superclass have access to and what performance implications it may have wrt virtual methods etc. Composition is quite basic and requires very little language support, and thus implementations across different platforms / frameworks can share composition patterns more easily.

Composition is a very simple and tactile way of building objects
Inheritance is relatively easy to understand, but still not as easily demonstrated in real life. Many objects in real life can be broken down into parts and composed. Say a bicycle can be built using two wheels, a frame, a seat, a chain etc. Easily explained by composition. Whereas in an inheritance metaphor you could say that a bicycle extends a unicycle, somewhat feasible but still much further from the real picture than composition (obviously this is not a very good inheritance example, but the point remains the same). Even the word inheritance (at least of most US English speakers I would expect) automatically invokes a meaning along the lines "Something passed down from a deceased relative" which has some correlation with its meaning in software, but still only loosely fits.

Composition is almost always more flexible
Using composition you can always choose to define your own behavior or simply expose that part of your composed parts. This way you face none of the restrictions that may be imposed by an inheritance hierarchy (virtual vs. non-virtual etc.)

So, it could be because Composition is naturally a simpler metaphor that has less theoretical constraints than inheritance. Furthermore, these particular reasons may be more apparent during design time, or possibly stick out when dealing with some of the pain points of inheritance.

Disclaimer:
Obviously its not this clear cut / one way street. Each design merits evaluation of several patterns / tools. Inheritance is widely used, has lots of benefits and many times is more elegant than composition. These are just some possible reasons one could use when favoring composition.

TJB
  • 297
  • 1
  • 12
  • 1
    "Obviously its not this clear cut / one way street." When is composition not more (or equally) flexible than inheritance? I would argue that it very much *is* a one-way street. Inheritance is just syntactic sugar for a special case of composition. – weberc2 Dec 12 '15 at 04:05
  • Composition is often _not_ flexible when using a language that implements composition using **explicitly implemented** interfaces, because those interfaces are not allowed to evolve in a backward-compatible manner over time. #jmtcw – MikeSchinkel May 10 '19 at 21:53
11

Perhaps you just noticed people saying this in the last few months, but it has been known to good programmers for a lot longer than that. I've certainly been saying it where appropriate for about a decade.

The point of the concept is that there is a large conceptual overhead to inheritance. When you are using inheritance, then every single method call has an implicit dispatch in it. If you have deep inheritance trees, or multiple dispatch, or (even worse) both, then figuring out where the particular method will dispatch to in any particular call can become a royal PITA. It makes correct reasoning about the code more complex, and it makes debugging harder.

Let me give a simple example to illustrate. Suppose that deep in an inheritance tree, someone named a method foo. Then someone else comes along and adds foo at the top of the tree, but doing something different. (This case is more common with multiple inheritance.) Now that person working at the root class has broken the obscure child class and probably doesn't realize it. You could have 100% coverage with unit tests and not notice this breakage because the person at the top wouldn't think of testing the child class, and the tests for the child class don't think of testing the new methods created at the top. (Admittedly there are ways to write unit tests that will catch this, but there are also cases where you can't easily write tests that way.)

By contrast when you use composition, at each call it is usually clearer what you are dispatching the call to. (OK, if you're using inversion of control, for instance with dependency injection, then figuring out where the call goes can also get problematic. But usually it is simpler to figure out.) This makes reasoning about it easier. As a bonus, composition results in having methods segregated from each other. The above example should not happen there because the child class would move off to some obscure component, and there is never a question about whether the call to foo was intended for the obscure component or the main object.

Now you are absolutely right that inheritance and composition are two very different tools that serve two different types of things. Sure inheritance carries conceptual overhead, but when it is the right tool for the job, it carries less conceptual overhead than trying to not use it and do by hand what it does for you. Nobody who knows what they are doing would say that you should never use inheritance. But be sure it is the right thing to do.

Unfortunately many developers learn about object oriented software, learn about inheritance, and then go out to use their new axe as often as possible. Which means that they try to use inheritance where composition was the right tool. Hopefully they will learn better in time, but frequently this does not happen until after a few removed limbs, etc. Telling them up front that it is a bad idea tends to speed up the learning process and reduce injuries.

btilly
  • 18,250
  • 1
  • 49
  • 75
  • 3
    All right, I guess that makes sense from a C++ perspective. That's something I never thought of, because it's not an issue in Delphi, which is what I use most of the time. (There's no multiple inheritance, and if you have a method in a base class and another method by the same name in a derived class that does not override the base method, the compiler will issue a warning, so you don't accidentally end up with this sort of problem.) – Mason Wheeler Apr 04 '11 at 23:51
  • 1
    @Mason: Ander's version of Object Pascal (a.k.a. Delphi) is superior to C++ and Java when it comes to the fragile base class inheritance problem. Unlike C++ and Java, overloading of an inherited virtual method is not implicit. – bit-twiddler Apr 05 '11 at 01:37
  • 2
    @bit-twiddler, what you say about C++ and Java can be said about Smalltalk, Perl, Python, Ruby, JavaScript, Common Lisp, Objective-C, and every other language I've learned that provides any form of OO support. That said, googling suggests that C# follows Object Pascal's lead. – btilly Apr 05 '11 at 01:57
  • 3
    That's because Anders Hejlsberg designed Borland's flavor of Object Pascal (a.k.a. Delphi) and C#. – bit-twiddler Apr 05 '11 at 02:15
9

In one of the comment, Mason mentionned that one day we would be speaking about Inheritance considered harmful.

I hope so.

The problem with inheritance is at once simple, and deadly, it does not respect the idea that one concept should have one functionality.

In most OO-languages, when inheriting from a base class you:

  • inherit from its interface
  • inherit from its implementation (both data and methods)

And here become the trouble.

This is not the only approach, though 00-languages are mostly stuck with it. Fortunately interfaces / abstract classes exist in those.

Also, the lack of ease for doing otherwise contribute to making it largely used: frankly, even knowing this, would you inherit from an interface and embed the base class by composition, delegating most of the method calls ? It would be considerably better though, you'd even be warned if suddenly a new method pops in the interface and would have to choose, consciously, how to implement it.

As a counter-point, Haskell only allow to use the Liskov Principle when "deriving" from pure interfaces (called concepts) (1). You cannot derive from an existing class, only composition allow you to embed its data.

(1) concepts may provide a sensible default for an implementation, but since they have no data, this default can only be defined in term of the other methods proposed by the concept or in term of constants.

Matthieu M.
  • 14,567
  • 4
  • 44
  • 65
8

The simple answer is: inheritance has greater coupling than composition. Given two options, of otherwise equivalent qualities, choose the one that is less coupled.

Jeffrey Faust
  • 1,520
  • 1
  • 9
  • 5
  • 2
    But that's the whole point. They're *not* "otherwise equivalent." Inheritance enables Liskov substitution and polymorphism, which are the entire point of using OOP. Composition doesn't. – Mason Wheeler Apr 05 '11 at 03:11
  • 4
    Polymorphism/LSP are not "the whole point" of OOP, they are one feature. There is also encapsulation, abstractions etc. Inheritence implies an "is a" relationship, agregation models a "has a" relationship. – Steve Apr 05 '11 at 09:18
  • @Steve: You can do abstractions and encapsulation in any paradigm that supports the creation of data structures and procedures/functions. But polymorphism (specifically referring to virtual method dispatching in this context) and Liskov substitution are unique to object-oriented programming. That's what I meant by that. – Mason Wheeler Apr 05 '11 at 14:59
  • 3
    @Mason: The guideline is to "favor composition over inheritance." In no way does this mean don't use or even avoid inheritance. All it says that when all other things are equal, choose composition. But if you need inheritance, use it! – Jeffrey Faust Apr 05 '11 at 20:27
8

It's a reaction to the observation that OO beginners tend to use inheritance when they don't need to. Inheritance is certainly not a bad thing, but it can be overused. If one class just needs functionality from another, then composition will probably work. In other circumstances, inheritance will work and composition won't.

Inheriting from a class implies a lot of things. It implies that a Derived is a type of Base (see the Liskov Substitution principle for the gory details), in that whenever you use a Base it would make sense to use a Derived. It gives the Derived access to the protected members and member functions of Base. It's a close relationship, meaning it has high coupling, and changes to one are more likely to require changes to the other.

Coupling is a bad thing. It makes programs harder to understand and modify. Other things being equal, you should always select the option with less coupling.

Therefore, if either composition or inheritance will do the job effectively, choose composition, because it's lower coupling. If composition will not do the job effectively, and inheritance will, choose inheritance, because you have to.

David Thornley
  • 20,238
  • 2
  • 55
  • 82
  • "In other circumstances, inheritance will work and composition won't." When? Inheritance can be modeled using composition and interface polymorphism, so I'd be surprised if there are any circumstances for which composition won't work. – weberc2 Dec 12 '15 at 04:12
8

Here are my two cents (beyond all the excellent points already raised):

IMHO, It comes down to the fact that most programmers don't really get inheritance, and end up overdoing it, partially as a result of how this concept is taught. This concept exists as a way to try to dissuade them from overdoing it, instead of focusing on teaching them how to do it right.

Anyone who has spent time teaching or mentoring knows that this is what often happens, especially with new developers who have experience in other paradigms:

These developers initially feel that inheritance is this scary concept. So they end up creating types with interface overlaps (e.g., same specified behavior without common subtyping), and with globals for implementing common pieces of functionality.

Then (often as a result of overzealous teaching), they learn about the benefits of inheritance, but it's often taught as the catch-all solution to reuse. They end up with a perception that any shared behavior must be shared through inheritance. This is because the focus is often on implementation inheritance rather than subtyping.

In 80% of the cases that's good enough. But the other 20% are where the problem starts. For the sake of avoiding rewriting and for making sure they have taken advantage of sharing implementation, they start designing their hierarchy around the intended implementation rather than the underlying abstractions. The "Stack inherits from doubly-linked list" is a good example of this.

Most teachers do not insist on introducing the concept of interfaces at this point, because it's either another concept, or because (in C++) you have to fake them using abstract classes and multiple inheritance which is not taught at this stage. In Java, many teachers do not distinguish the "no multiple inheritance" or "multiple inheritance is evil" from the importance of interfaces.

All this is compounded by the fact that we've learned so much of the beauty of not having to write superfluous code with implementation inheritance, that tons of straightforward delegation code looks unnatural. So composition looks messy, which is why we need these rules of thumbs to push new programmers to use them anyway (which they overdo as well).

Uri
  • 4,836
  • 1
  • 18
  • 23
  • Thats a true part of education. You have todo the higher courses to get i.e. the rest of 20% but you, as the student, was just teached the basic and and perhaps intermediate courses. In the ending, you feel well teached because you did your courses well (and simply dont see it just a pin on the ladder). It's just a part of reality and our best bet is to understand it's side effects, not attack the coders. – Independent Apr 19 '12 at 05:24
7

I think this sort of advice is like saying "prefer driving to flying". That is, planes have all sorts of advantages over cars, but that comes with a certain complexity. So if many people try to fly from the city centre to the suburbs, the advice they really, really need to hear is that they don't need to fly, and in fact, flying will just make it more complicated in the long run, even if it seems cool/efficient/easy in the short term. Whereas when you do need to fly, it's generally supposed to be obvious.

Likewise, inheritence can do things composition can't, but you should use that when you need it, and not when you don't. So if you're never tempted to just assume you need inheritence when you don't, then you don't need the advice of "prefer composition". But many people do, and do need that advice.

It's supposed to be implicit that when you really DO need inheritance, it's obvious, and you should use it then.

Also, Steven Lowe's answer. Really, really that.

Kazark
  • 1,810
  • 1
  • 17
  • 37
Jack V.
  • 1,120
  • 7
  • 6
3

Inheritance isn't inherently bad, and composition isn't inherently good. They are merely tools that an OO programmer can use to design software.

When you look at a class, is it doing more than it absolutely should (SRP)? Is it duplicating functionality unnecessarily (DRY), or is it overly interested in the properties or methods of other classes (Feature Envy)?. If the class is violating all of these concepts (and possibly more), is it attempting to be a God Class. These are a number of problems that can occur when designing software, none of which is necessarily an inheritance problem, but which can quickly create major headaches and brittle dependencies where polymorphism has also been applied.

The root of the problem likely to be less a lack of understanding about inheritance, and more one of either poor choice in terms of design, or perhaps not recognizing "code smells" relating to classes that are not adhering to the Single Responsibility Principle. Polymorphism and Liskov Substitution need not be discarded in favour of composition. Polymorphism itself can be applied without relying on inheritance, these are all quite complimentary concepts. If applied thoughtfully. The trick is to aim to keep your code simple, and clean, and to not to succumb to being overly concerned about the number of classes that you need to create in order to create a robust system design.

In so far as the issue of favouring composition over inheritance, this is really just another case of the thoughtful application of the design elements that make the most sense in terms of the problem being solved. If you don't need to inherit behaviour, then you probably shouldn't as composition will help to avoid incompatibilities and major refactoring efforts later on. If on the other hand you find that you are repeating a lot of code such that all of the duplication is centred on a group of similar classes, then it may be that creating a common ancestor would help to reduce the number of identical calls and classes you might need to repeat between each class. Thus, you are favouring composition, yet you aren't assuming that inheritance is never applicable.

S.Robins
  • 11,385
  • 2
  • 36
  • 52
0

To favor composition over inheritance was taken from the Erich Gamma book, Design Patterns. It might be on page 20 or so, it was in reference to Java development, I believe.

Nonetheless, people in the JavaScript community have latched onto this phrase and used it as a selling point to say hey we should favor object composition.

Here is the issue, this is probably the most misunderstood statement ever, in the JavaScript community. Now the statement itself is correct, the author themselves go on to give a very strong argument for saying we should favor object composition, the issue is that if you go on to Google right now and search for JavaScript composition versus inheritance and view all these different blogposts and videos, if you read them, you will find that their definition of composition is 100% incorrect.

So maybe composition versus inheritance is some debatable topic, the issue is that everyone’s understanding of the word composition in the Javascript world is just plain wrong.

So my goal here is to help you understand what the authors of the book were talking about when they wrote that statement and what the people who are writing all these blogposts are talking about when they are writing about composition and my goal here is not to shame anyone in the JavaScript community, that’s not what I am here to do.

I am just trying to make clear that we really messed up the definition of composition and its important for us to correct that understanding and correct that definition, otherwise, we got tons of engineers who are going to be writing really weird code because they think these authors, the authors of this book Design Patterns: Elements of Reusable Object-Oriented Software that I am going to take a look at, were saying one thing, when in fact they were saying a very different other thing.

So, let's get to it.

I am going to first take a look at the book, get an understanding of their definition of composition, then take a look at a blog post and get the blog post definition of composition and compare and contrast the two and I think you will find they are extremely different definitions of composition.

Inside of Design Patterns, a book that was written many years ago, it was not written specifically for JavaScript, I will go down to page 40 or so and it says here very clearly:

Favor object composition over class inheritance

and again this is the phrase that gets repeated hundreds of times.

So let's take a look at this books definition of what composition is.

I am going to scroll down just a bit to the next section which is about Delegation and they are saying the delegation pattern is one way of making composition a very strong pattern, the exact quote is:

Delegation is a way of making composition as powerful for reuse as inheritance [Lie86,JZ911. In delegation, two objects are involved in handling a request: a receiving object delegates operations to its delegate. This is analogous to subclasses deferring requests to parent classes. But with inheritance, an inherited operation can always refer to the receiving object through the this member variable in C++ and self in Smalltalk. To achieve the same effect with delegation, the receiver passes itself to the delegate to let the delegated operation refer to the receiver.

So delegation is kind of like a tool or method of implementing composition.

They go on to describe exactly how delegation works. So let’s take a look at their example of how delegation works here. They are saying instead of making a Window a subclass of rectangle, just because the window happens to be rectangular, the Window class might instead reuse the rectangle, and here is the really important part, keeping a reference to the rectangle instance variable and delegating Rectangle specific behavior to it.

For example, instead of making class Window a subclass of Rectangle (because windows happen to be rectangular), the Window class might reuse the behavior of Rectangle by keeping a Rectangle instance variable and delegating Rectangle-specific behavior to it. In other words, instead of a Window being a Rectangle, it would have a Rectangle. Window must now forward requests to its Rectangle instance explicitly, whereas before it would have inherited those operations.

So a Window should have a reference to a Rectangle and they offer a diagram in their book, but I recreated it here: enter image description here

So I said that a Window should have a reference to a Rectangle or generally some kind of shaped object and I can easily swap that object out and that’s how we get code reuse.

SO when the book talks about composition, they are saying, very specifically, we are going to favor delegation as a pattern to implement composition. With this pattern we have some class that has a reference to another object and anytime some request comes in to get the area of the window, the Window class will delegate that calculation off to the outside object.

So that is what the book is saying when it talks about composition.

Let's take a look at an example blogpost where they get it wrong:

const canCast = (state) => ({
    cast: (spell) => {
        console.log(`${state.name} casts ${spell}!`);
        state.mana--;
    }
})

const canFight = (state) => ({
    fight: () => {
        console.log(`${state.name} slashes at the foe!`);
        state.stamina--;
    }
})

const fighter = (name) => {
  let state = {
    name,
    health: 100,
    stamina: 100
  }
  
  return Object.assign(state, canFight(state));
}

const mage = (name) => {
  let state = {
    name,
    health: 100,
    mana: 100
  }
  
  return Object.assign(state, canCast(state));
}

scorcher = mage('Scorcher')
scorcher.cast('fireball');    // Scorcher casts fireball!
console.log(scorcher.mana)    // 99

slasher = fighter('Slasher')
slasher.fight();              // Slasher slashes at the foe!
console.log(slasher.stamina)  // 99

Again, I am not trying to shame anyone, just trying to clarify a misunderstanding.

So in the above example, the original author of this code is creating a function here called fighter.

Then inside of fighter, whenever they call it they are going to create an object that they call state and state has some different properties that describe a fighter.

Now a fighter needs to have some number of methods attached to it to actually make this object useful. So here, they are saying Object.assign() like so:

   const fighter = (name) => {
      let state = {
        name,
        health: 100,
        stamina: 100
      }
      
      return Object.assign(state, canFight(state));
    }

Object.assign() is going to take all the different properties out of this object canFight(state) and essentially copy paste them over to this object, state.

Does this not sound a lot like inheritance?

Yes, it kind of does, let's keep that in mind.

So, obviously, we need to understand what canFight() does right here.

canFight is defined right here:

const canFight = (state) => ({
    fight: () => {
        console.log(`${state.name} slashes at the foe!`);
        state.stamina--;
    }
})

So they pass in that state object that has all their instance variables tied to it.

And then inside of canFight all they are doing is returning an object that has some different methods attached to it and the idea is that these methods right here are going to attempt to work on those instance properties like name, stamina, health and so on.

So when these authors of blogposts are talking about composition they are using the literal definition of composition as found in the English dictionary.

They are saying oh yeah we are using composition because we have the ability to build up an object by composing it from multiple different sources of methods. So yeah the word composition in the absolute sense of the English language, sure I can buy that, but the issue is, when quoting the book that says

favor composition over class inheritance

Those are two different types of compositions that are being addressed here.

The authors of Design Patterns are saying one object has a reference to this other object or other objects. All the blogposts are saying, let's build up the definition of an object by using different sets of methods.

To ensure we are clear what these blog posts are saying,

I will write out a really quick example to emulate how I would build up the definition of a Window.

I will follow the same pattern I just saw in that blogpost.

So I will write out a function called rectangular and the goal of this function is to take in some state object like so:

const rectangular = (state) => {}

And remember it has some instance variables tied to it and then I am going to return an object that has some methods that I am going to eventually use in some definition of something that is rectangular like so:

const rectangular = (state) => {
    return {
  
  };
};

If something is rectangular then chances are I want it to have an area() method like so:

const rectangular = (state) => {
    return {
    area: () => {}
  };
};

So I gave it an area method and inside of here I will return state.height * state.width like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

So I am very clearly making the implication that state object that is coming in, must have a height and a width property. After that I will define maybe some openable function like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {};

And the goal of this is to give a door presumably, the ability to toggle itself open or closed and I will do that by returning an object that has methods to implement that behavior like a method called toggleOpen like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {}
  };
};

And inside of here I will say state.open is the opposite of state.open, so that is definitely some toggling behavior like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {
        state.open = !state.open;
    }
  };
};

Now here is the important part, to combine or compose them into an object, I would write a single function called buildRectangleWindow that will be called with some state object like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {
        state.open = !state.open;
    }
  };
};

const buildRectangleWindow = (state) => {};

Now this example is slightly different than the code I got from the blogpost. In the blogpost they define that state object directly inside the function that was intended to actually build an instance of an object, I am going to pass in those instance properties as an argument because that is way more flexible than what the example had.

So then inside of buildRectangleWindow I will say return Object.assign(state, rectangular(state), openable(state));` like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {
        state.open = !state.open;
    }
  };
};

const buildRectangleWindow = (state) => {
    return Object.assign(state, rectangular(state), openable(state));
};

I am basically saying take the state object, throw it into openable, when I call openable, it's going to return an object that has some methods on it. Then take the state object and throw it into rectangular and same idea. So essentially this openable is going to return an object that has some method on it, rectangular is going to return an object that has some method on it and then I will take all those different methods and copy paste them down to the state object.

Now, to actually create an rectangular window I would do the following:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {
        state.open = !state.open;
    }
  };
};

const buildRectangleWindow = (state) => {
    return Object.assign(state, rectangular(state), openable(state));
};

const rectangleWindow = buildRectangleWindow({
    height: 20,
  width: 20,
  open: false
});

Now to actually use this object, I can do this like:

rectangleWindow.open

To see whether or not the window is open or not and I get false as the output.

I can also do:

rectangleWindow.toggleOpen();

That should toggle the open status and I can print out rectangleWindow again like so:

rectangleWindow.open

And now I get true.

So the entire idea behind this approach is that we have these separate definitions of methods and I am going to combine them together to actually build a usable object.

So when all these blogposts are using the term composition, I can buy into that this is some form of composition in the strictest sense of the literal English definition of composition, because we are composing the behaviors of an object by combining them together, but the point is that this is not the same definition of composition as you find in the Design Pattern book and that book is what everyone is quoting.

Erich Gamma and the other authors are extremely smart people who said you should use this pattern right here over class inheritance and then the blogpost authors are saying when they said composition, they meant this thing and that is just not what the authors of Design Patterns are talking about.

Erich Gamma and his co-authors were not saying to do, what I just illustrated in the code above.

This is just not a good pattern and I can show you why this is not a good pattern very easily.

Let’s say for some reason openable also has an area method like so:

const rectangular = (state) => {
    return {
    area: () => {
        state.height * state.width;
    }
  };
};

const openable = (state) => {
    return {
    toggleOpen: () => {
        state.open = !state.open;
    },
    area: () => {};
  };
};

const buildRectangleWindow = (state) => {
    return Object.assign(state, rectangular(state), openable(state));
};

const rectangleWindow = buildRectangleWindow({
    height: 20,
  width: 20,
  open: false
});

rectangleWindow.open
rectangleWindow.toggleOpen();
rectangleWindow.open

So, what does that mean? It means that when I have some object that combines the methods from rectangular and openable, which area method are we going to actually get?

The area method we end up getting comes down to the order in which we list them out in the Object.assign() statement.

So this entire pattern here is incredibly fragile. If you ever happen to have any methods with the same name. If you ever do, that’s pretty much it, you cannot combine those different sets of methods together because you are going to get super unexpected behavior.

So the same author of the code, called all this  concatenative inheritance. What it really is, is multiple inheritance like so:

enter image description here

Thats what we are really doing here. We are building up the definition of some rectangleWindow by combining all the different methods that are openable and rectangular. So you can kind of imagine that yep, I am going to copy paste, literally, in this case, all those methods from openable and rectangular down to rectangleWindow.

Again that looks an awful lot like inheritance.

So it is not composition, but multiple inheritance. They are inheriting methods from multiple different sources.

I hope I have provided a better idea on what Erich Gamma and his co-authors were talking about when they were discussing object composition.

Daniel
  • 119
  • 7
  • 1
    JavaScript devs *should* be shamed, for taking a toy language that was intended for nothing more than [to make the monkey dance when you mouse over it](https://softwareengineering.stackexchange.com/a/221658/935) and building it up into a massive franken-hack that incorporates [every mistake in the history of programming and invents a few more.](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html) And *especially* for Node and NPM; the folks who foisted *that* abomination on the would should be placed in the stocks for some good old-fashioned public shaming! – Mason Wheeler Sep 06 '21 at 11:55
  • @MasonWheeler, thank you for sharing. – Daniel Sep 06 '21 at 14:55
  • 1
    @MasonWheeler, if i am being honest, I really got a kick out of how Wall invented Perl, I used to live in a county in a certain state of the United States, where most businesses were still using Perl and it was already 2015, I knew I was living in the wrong part of the world. Baby boomers are the majority in that county and in conversation they offer a knee-jerk reactionary laugh at the utterance of the phrase "electric car" like its still 1953. – Daniel Sep 06 '21 at 15:05
  • Did you create those diagrams yourself? – JonnyIrving Dec 02 '21 at 10:32
-1

The actual quote comes, I believe, from Joshua Bloch's "Effective Java", where it is the title of one of the chapters. He claims that inheritance is safe within a package and wherever a class has been specifically designed and documented for extension. He claims, as others have noted, that inheritance breaks encapsulation because a subclass depends on the implementation details of its superclass. This leads, he says, to fragility.

Although he doesn't mention it, it seems to me that single inheritance in Java means that composition gives you much more flexibility than inheritance.