Side by side
CompositionvsInheritance
What is the difference between composition and inheritance?
Updated 3 min read8 differences
In short
Composition reuses code by holding other objects and delegating to them (has-a); inheritance reuses it by extending a parent class (is-a).
Composition
Composition builds an object out of other objects that it holds and delegates work to, modeling a has-a relationship instead of inheriting from a parent class.
Read the page on CompositionInheritance
Inheritance is an object-oriented programming feature that lets a new class reuse, extend, and override the fields and methods of an existing class.
Read the page on InheritanceComposition and Inheritance compared
| Aspect | Composition | Inheritance |
|---|---|---|
| Relationship | has-a: a car has an engine | is-a: a dog is an animal |
| How code is reused | By delegating calls to objects held in fields | By inheriting fields and methods from a parent class |
| Coupling | Loose: depends only on the parts' interfaces | Tight: a subclass depends on its parent's internals |
| When it is fixed | Parts can be chosen at runtime or swapped in tests | Fixed when the class is written |
| Combining features | Mix parts freely, such as an engine and a driver | Each combination may need its own subclass |
| Amount of code | More: each delegating method is written out | Less: inherited methods come for free |
| Polymorphism | Through shared interfaces | Through overriding the parent's methods |
| Language support | Every language; Go and Kotlin add built-in help | Most OOP languages; Go has no class inheritance |
The difference, explained
Composition and inheritance are the two main ways to reuse code in object-oriented programming. Composition builds a class from other objects that it holds in fields and delegates work to, modeling a has-a relationship: a Car has an Engine. Inheritance creates a new class from an existing one, which gets the parent's fields and methods and can override them, modeling an is-a relationship: a Dog is an Animal.
The essential difference is coupling. A subclass depends on its parent's internals, so a change in the parent can break every child, and the hierarchy is fixed when the code is written; when features combine, subclasses multiply into ElectricCar, HybridCar and SelfDrivingElectricCar. With composition, the parts usually sit behind interfaces, so they can be chosen at runtime, swapped, or replaced by fakes in tests. The cost is a little more code, since each delegating method has to be written.
"Favor object composition over class inheritance" comes from the 1994 book Design Patterns by the Gang of Four, and patterns such as strategy, decorator and dependency injection are built on it. It is a preference, not a ban: inheritance remains the right tool for true is-a relationships, such as a custom error type that extends Error, and most real designs use both, inheriting from a small base class or implementing an interface and composing the rest. Some languages lean toward composition by design: Go has no class inheritance and embeds structs instead, and Kotlin delegates a whole interface to a field with by.
A common misconception is that inheritance is needed for polymorphism. Interfaces give the same ability to treat different objects alike, without sharing code. Another is that inheritance is a good way to reuse a handy method; extending a class only for its code creates the tight coupling that composition avoids. The simple test is one question: is it a kind of X, or does it have or use an X?
Which one should you use?
Choose Composition when…
- One object has or uses another, such as a car and its engine.
- Behavior should be swappable at runtime or replaced with a fake in tests.
- Features combine in many ways that would multiply subclasses.
- You want to reuse a class you don't control without depending on its internals.
Choose Inheritance when…
- One type truly is a kind of another and can be used wherever the parent is expected.
- A framework expects you to extend its base class, such as
Erroror a UI component class. - The hierarchy is shallow and stable, and subclasses share most of the parent's code.
Cars with different engines, both ways (TypeScript)
// Composition: a Car HAS an engine and delegates to it
interface Engine { start(): string; }
class PetrolEngine implements Engine { start() { return "vroom"; } }
class ElectricEngine implements Engine { start() { return "hum"; } }
class Car {
constructor(private engine: Engine) {}
start() { return `Car: ${this.engine.start()}`; }
}
new Car(new ElectricEngine()).start(); // "Car: hum", any engine fits// Inheritance: each kind of car IS a Car and overrides a method
class Car {
start() { return `Car: ${this.sound()}`; }
protected sound() { return "..."; }
}
class PetrolCar extends Car { protected sound() { return "vroom"; } }
class ElectricCar extends Car { protected sound() { return "hum"; } }
// Every new combination needs another subclass
class SelfDrivingElectricCar extends ElectricCar { /* ... */ }
new ElectricCar().start(); // "Car: hum"Readers ask
What does "composition over inheritance" mean?
It is a design guideline: to reuse behavior, prefer holding an object that provides it over extending a class that has it. Inheritance isn't forbidden; it is kept for true is-a relationships.
Is inheritance bad?
No. It is the right tool when one type truly is a kind of another and the hierarchy stays shallow. The trouble comes from deep trees and from inheriting only to reuse code.
How does Go work without inheritance?
Go has no classes. It embeds one struct in another, which makes the embedded type's methods available on the outer one, and uses interfaces for polymorphism, so reuse happens through composition.