DEV Community

Discussion on: Why composition is superior to inheritance as a way of sharing code

Collapse
 
jim_ej profile image
James Ellis-Jones

The article misses out polymorphism which is the key use case for inheritance. You can't use a class which is composed of another class in the same context as the second class.

It also overstates issues with testing and lack of clarity of child classes. It requires a little thought but it's easy enough to do constructor injection with class hierarchies.

A good example where inheritance is essential is in presentation: it's vital to be able to process a range of similar but different visual components with the same code. Such visual components typically share a lot of internal code so interface polymorphism is not a good fit.

Like many issues, inheritance and composition are both valid approaches in different context rather than one being 'better' than the other

Collapse
 
cullophid profile image
Andreas Møller

Do you have an example where subtype polymorphism cannot be replaced by composition and interface polymorphism?

Collapse
 
pnambic profile image
Daniel Schmitt • Edited

One example would be a requirement to enforce behavioural invariants (one of the aspects of the Liskov substitution principle aka the L in SOLID). The compiler can't verify that you followed some rule in the dev manual that says, "all classes implementing IDependency must implement method x() by calling _dep.x(), and only _dep.x()". But, if you express that rule through final/non-virtual methods on a base class instead, then it can, and as a bonus it's self-documenting.

Another example, from a maintainability point of view: imagine having 42 classes implementing IDependency and a requirement to extend that interface with a new set of methods. Would you rather touch one or two files, or all 44 of them, even if the changes are mostly trivial? Java 8 added inheritance of default implementations to interfaces to support that exact scenario.

Lastly, imagine you would like to inherit several levels of bases because your problem domain is hierarchically structured, you need to conclusively demonstrate correctness in some parts, and want to leverage the type system to do that. So you end up with something like InvoicePaid (detailed business rule level) inheriting from TaxAccountable (legally required, with external code audit) inheriting from Financial (security rules about event routing) inheriting from Event (shared technical infrastructure).

Interface inheritance can usually deal with the correctness issue, because while the relevant behaviour depends on the type, it's typically implemented external to it (unlike in the first example), but imagine what a leaf class implementation would look like if these were more than just marker interfaces. And they will be, and you'll have lots of leaves.

What this boils down to is: every language supporting OO implementation design supports some form of implementation inheritance and also some form of composition (AFAIK), and there are good reasons for that. Traditionally, inheritance has been oversold by OO teaching materials, and overused as a result, but avoiding it completely is overreacting.

Collapse
 
ruidfigueiredo profile image
Rui Figueiredo

Hi James,

The article starts by distinguishing implementation inheritance from interface inheritance. And specifically the use of implementation inheritance as a way to share code (this is where you have a base class and you derive from it to access its methods, no polymorphism is used here).

If you are talking about inheritance being essential in presentation specifically to take advantage of polymorphism them I agree, but that was not the point of the article.

Collapse
 
jim_ej profile image
James Ellis-Jones

Hi Rui

Thanks for your response. My apologies that I misunderstood your limitation of the point you were making. I think we can then agree that in cases where you need polymorphism together with sharing code, inheritance has it's uses, but where polymorphism is not relevant, composition is preferable.