151

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?

14
  • 48
    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): artima.com/lejava/articles/designprinciples4.html
    – Janx
    Apr 4 '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. Apr 5 '11 at 0:13
  • 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 5 '11 at 8:33
  • 8
    Last few months?!?
    – Jas
    Apr 5 '11 at 12:41
  • 6
    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 5 '11 at 15:04

15 Answers 15

148

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>

23
  • 16
    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. Apr 5 '11 at 2:06
  • 15
    There should be a word for this kind of thing. Premature Regurgitation, maybe? Apr 5 '11 at 2:08
  • 8
    @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?) Apr 5 '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 6 '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." ;) Apr 19 '12 at 3:56
76

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.

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? Apr 4 '11 at 23:08
  • 14
    @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. Apr 4 '11 at 23:14
  • 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 4 '11 at 23:27
  • 6
    @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." Apr 4 '11 at 23:46
  • 8
    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
44

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.

6
  • 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. Apr 4 '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 4 '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. Apr 4 '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. Apr 5 '11 at 0: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. Apr 19 '12 at 4:03
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".

26

"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..."

1
  • 4
    Very good example with the Snake. I met a similar case recently with my own classes
    – Maksee
    Apr 19 '12 at 6:59
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.

2
  • 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 4: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 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.

4
  • 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.) Apr 4 '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. Apr 5 '11 at 1: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 5 '11 at 1:57
  • 3
    That's because Anders Hejlsberg designed Borland's flavor of Object Pascal (a.k.a. Delphi) and C#. Apr 5 '11 at 2: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.

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.

1
  • "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 4: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).

1
  • 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. Apr 19 '12 at 5:24
7

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

4
  • 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. Apr 5 '11 at 3: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 5 '11 at 9: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. Apr 5 '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! Apr 5 '11 at 20:27
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.

1
  • 1
    I like your analogy
    – barrylloyd
    Apr 5 '11 at 12:24
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.

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.

3
  • 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 and building it up into a massive franken-hack that incorporates every mistake in the history of programming and invents a few more. 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! Sep 6 at 11:55
  • @MasonWheeler, thank you for sharing.
    – Daniel
    Sep 6 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 6 at 15:05
-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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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