Tony Marston's Blog About software development, PHP and OOP

RE: The purpose of inheritance is code reuse

Posted on 1st May 2021 by Tony Marston
Introduction
Point #1
Point #2
Point #3
Point #4
Point #5
Conclusion
Comments

Introduction

I regularly peruse the PHP internals list to see what abominations are being proposed for inclusion into the language, and occasionally I come across a comment which leads me to believe that the author of that comment doesn't quite get what OOP actually means, and instead of introducing clarity into the discussion is doing the exact opposite by muddying the waters with weird interpretations. One such questionable statement was made in https://news-web.php.net/php.internals/114202 where Guilliam Xavier said:

I have created a Draft RFC here: https://wiki.php.net/rfc/sealed_classes
To me the first sentence of the RFC is debatable:
The purpose of inheritance is code reuse, for when you have a class that shares common functionality, and you want others to be able to extend it and make use of this functionality in their own class.
That sounds like [abstract] base classes, which certainly permit that, but I wouldn't state that "the purpose" of [designing] class hierarchies is "code reuse", which can also (better?) be achieved with traits or even simply composition

My reply to him was this:

I completely disagree that the first sentence of that RFC is debatable as I consider it to be totally accurate. When you use inheritance via the 'extends' keyword then every method in the superclass is shared by the subclass. In the subclass you have the option to override the implementation of any method in the superclass, or you can add new methods of your own. This superclass may be abstract, but it need not be. The methods it contains may be abstract, but they need not be.

According to the Gang of Four the way to avoid the problems caused by the overuse of inheritance is to only inherit from an abstract class, which is precisely what I do. I am famous for having an abstract table class in my framework which contains hundreds of methods and thousands of lines of code, and because each of my 400 concrete table classes inherits from the same abstract table class that is a LOT of code which is shared. This abstract table class also allows me to use the Template Method Pattern (which is also mentioned in the Gang of Four book) so that all the invariant methods are defined in the abstract class which means that each subclass need only contain the variable "hook" methods for which it needs to provide an implementation.

When you say that code reuse can be better achieved with traits or object composition I have to disagree. Object composition is used only by those idiots who overuse inheritance, and there is no evidence that traits are "better" than inheritance.

Inheritance, when used sensibly, is still the best way to share code.

Point #1

Guilliam responded with this:

But does that necessarily mean that "The purpose of inheritance is code reuse"?

To which I responded with:

Can you show me any description of OOP which says that the purpose of inheritance is anything other than code reuse? What other purpose could it possibly serve?

Guilliam responded with this:

I suspect it won't convince you but you can find quotes like: "The point of inheritance is to take advantage of polymorphic behavior NOT to reuse code, and people miss that, they see inheritance as a cheap way to add behavior to a class."

To which I responded with:

This statement is inaccurate on two counts:
  1. Inheriting a method does not necessarily mean that the method will be accessed in a polymorphic manner. Polymorphism is defined as "same method, different implementation", so if you inherit a concrete method and do not alter it there is no different implementation and therefore no point in calling it on different objects as the result will be the same.
  2. You do not need inheritance to provide polymorphic methods. All you need is the same method signature in multiple classes, and you can define each method manually in each of those classes without any inheritance whatsoever.

Point #2

To my question What other purpose could it possibly serve? he responded with:

Modeling a problem domain? Enforcing a contract?

To his answer Modeling a problem domain I responded with:

You do not need inheritance to model a problem domain, you just need classes, and you can create classes without inheritance. Besides, you cannot inherit the business logic in one domain and share it with another domain as the business logic is unique within each domain. It is possible to inherit boilerplate code which is domain-agnostic because that is precisely what I do in my framework with my abstract table class and its use of the Template Method Pattern.

To his answer Enforcing a contract I responded with:

A contract is just a fancy term for a method signature, and you don't need inheritance to provide method signatures.

Point #3

To my statement According to the Gang of Four the way to avoid the problems caused by the overuse of inheritance is to only inherit from an abstract class he responded with:

Well, PHP is flexible. I have seen many combinations of (one or several of) interface, [abstract] class, trait, composition... depending on the context.

This was my response:

The fact that there are now several ways of reusing code does not detract from the original statement that The purpose of inheritance is code reuse.

Point #4

To my statement there is no evidence that traits are "better" than inheritance he responded with:

By the way, is there evidence to the contrary? (genuine question)

This was my response:

Until somebody does a comparison of all the different ways in which code can be shared there can never be a definitive answer

Point #5

To my statement Inheritance, when used sensibly, is still the best way to share code he responded with:

Your opinion, maybe not unanimity (nor absolute truth).

My response was:

The GOF book says so, and it also says that the Template Method Pattern - which can only be used through inheritance - is a fundamental technique for code reuse. In my humble opinion any method of code reuse which does not allow the Template Method Pattern is automatically inferior.

To which he responded with:

Are The GoF Book opinions (still) unanimity?

I responded with:

While different people come up with different ideas as to what is right or wrong I ignore them unless their arguments are convincing. If anyone makes a questionable statement I have the right to question or challenge that statement. The fact that some people do not like their opinions being questioned points to a fault in their character.

Until somebody of high repute publishes a book which replaces what was produced by the Gang of Four, and explains why what they wrote is now out of date and offers alternative explanations that are accepted by the wider programming community I shall continue to accept what they wrote as being correct. Any Tom, Dick or Harry can jump up and say This is the new truth!, but unless they can provide convincing evidence I shall ignore them with impunity.

Conclusion

The idea that the purpose of inheritance is NOT code reuse strikes me as being totally preposterous. The purpose of inheritance is NOT polymorphism as you have to first share the same methods in multiple classes before you can obtain polymorphism. The purpose of inheritance is NOT to model a problem domain as those models are produced with classes, and you can create classes WITHOUT inheritance. The purpose of inheritance is NOT to enforce a contract as "contract" is just a fancy term for a method signature, and you don't need inheritance to create method signatures.

I do not overuse or abuse inheritance as I follow the advice in the GoF book and only ever inherit from an abstract class. In my ERP application I have over 450 concrete table (Model) classes which all inherit from the same abstract table class. Every public method in this abstract class is an instance of the Template Method Pattern which mixes invariant and variable "hook" methods. The invariant methods provide all the boilerplate code which supply the standard behaviour, while the "hook" can be overridden in any subclass to provide custom behaviour. Every one of my 40 reusable Page Controllers can be used with any of those 450 concrete table class simply because of the abundance of polymorphic methods. If I have 40 Controllers which can be used with 450 Models that gives me 40 x 450 = 18,000 (YES, EIGHTEEN THOUSAND) opportunities for polymorphism. This volume of reusability can ONLY be provided with the power of inheritance, so when some confused individual states that the purpose of inheritance is NOT code reuse is it any wonder that it provokes such a reaction?

When a novice programmer wants to learn how to write cost-effective software using the principles of OOP then coming across such misleading statements such as the one which is the purpose of this article can only lead the novice down the wrong path. I feel it is my duty to point out those incorrect statements and put the novice back on the correct path.

Here endeth the lesson. Don't applaud, just throw money.


counter