Hiprup

What is the difference between composition and inheritance?

Two ways to reuse and combine behaviour.

  • Inheritance — a class extends a parent, gaining its features (an "is-a" relationship). Deep hierarchies can become rigid.

  • Composition — build objects by combining small, focused pieces of behaviour (a "has-a" relationship). More flexible.

Common advice: "favour composition over inheritance" — it avoids tight coupling and fragile class trees.

// Inheritance
class Animal {
  speak() { return 'Some sound'; }
}
class Dog extends Animal {
  speak() { return 'Woof!'; }
}

// Composition (preferred)
const canSwim = (state) => ({
  swim: () => `${state.name} is swimming`
});

const canFly = (state) => ({
  fly: () => `${state.name} is flying`
});

const canWalk = (state) => ({
  walk: () => `${state.name} is walking`
});

// Duck can walk, swim, AND fly — no class hierarchy needed
function createDuck(name) {
  const state = { name };
  return {
    ...canWalk(state),
    ...canSwim(state),
    ...canFly(state),
    quack: () => `${name} says quack!`
  };
}

const duck = createDuck('Donald');
console.log(duck.swim());  // 'Donald is swimming'
console.log(duck.fly());   // 'Donald is flying'
console.log(duck.quack()); // 'Donald says quack!'

Inheritance: Dog extends Animal (single chain). Composition: canSwim, canFly, canWalk are mixins — combined freely with spread.

Duck composes all three behaviors without a class hierarchy. Adding a new behavior (canDive) is just another function — no refactoring the inheritance tree.

'Favor composition over inheritance' is the principle. Show the duck example: composing behaviors from multiple sources (impossible with single class inheritance).

Composition = loose coupling, easy testing, flexible combination. Inheritance = tight coupling, single chain.

What is the difference between composition and inheritance? | Hiprup