There is a software engineering principle that suggests to:

Prefer inheritance over composition.

Nah just kidding, it’s the opposite!

Prefer composition over inheritance.

Why Inheritance is Generally Bad

The reasons being that:

  • Inheritance introduces sneaky (hidden) behavior.
  • Understanding deep inheritance hierarchies are difficult.
  • Restricts flexibility in terms of mixing and matching behaviors.

Let’s expand on these.

Hidden Behavior

When you are looking at the source code of a component (class in this case), and the component inherits, you are missing a bunch of hidden methods/fields. You are not looking at the full picture of the class’s data/behavior. There is a hidden repository of behavior, the base class.

This situation is exacerbated when the base class also has a base class and so on; in other words, when the inheritance hierarchy is deep.

You may think that a class is very small and cohesive when in actuality it is not.

Understanding Deep Inheritance Hierarchies are Difficult

Deep inheritance hierarhcies require you to jump around several files to understand a single class. Typically one file for each class in the inheritance chain. This makes understanding them more difficult and thus maintainance more difficult.

Restricts Flexibility

There are well known problems with multiple inheritance (diamond inheritance problem). So if you “inherit” behavior you can only inherit it via the inheritance chain, a class cannot (reliably) “inherit” multiple behaviors by inheriting from multiple base classes.

This restricts your ability to mix and match behaviors in a derived class (because it can only inherit from one base class - reliably).

Composition to the Rescue

Instead of inheriting data/behavior (fields/methods) from a base class, just use the base class through composition (delegate to it).

When you need to inherit just behavior (just methods), just make free functions, no need to inherit at all.

When you need to also inherit data, create an instance of the class and delegate to it.

This way, if you need to inherit data/behavior from multiple “base” classes, you just create each of them as an instance variable and delegate to them!

This makes all the methods of your class explicit (even though most of them will simply be pass through methods).

Speaking of which, you will get a lot of pass through methods when choosing composition over inheritance, but the idea is that these additional pass through methods are worth 1) making the behavior explicty (no hidden behaviors) and more importantly 2) allowing mix and match flexibility.

Proper Application of Inheritance

Like most things in software engineering (and in life) things are not black and white. Inheritance isn’t always bad, and there are times when it is the perfect tool.

If you have a short inheritance hierarchy (2-3 levels) it can save you a lot of pass through functions. It is well suited for situations like in a GUI frameworks where you have a base GuiElement-like class with a ton of basic functionality common to all GUI widgets.

Summary

  • Yes, composition is generally better than inheritance.
  • But inheritance isn’t always bad.
    • Keep your inheritance hierarchies short.

Have an awesome day!