The Flaws of Inheritance - 2022

Details

Title : The Flaws of Inheritance Author(s): CodeAesthetic Link(s) : https://www.youtube.com/watch?v=hxGOiiR9ZKg

Rough Notes

Suppose there is an (abstract) Image class, which methods such as getPixelValue, flipHorizontal etc. If we want to implement a save and load method, this depends on the encoding so we need to implement these methods separately for different image formats such as png, jpg, bmp etc. In this case, we create a new class for each format which inherits from the Image class.

Now assume we want images where instead of loading them, we create them within the code itself, lets call the class for this DrawableImage - if we inherit from Image we also inherit the (unimplemented) save and load. The solution could be to create a new class FileImage that has the save and load methods, but now we have to do a lot of refactoring since now the save and load methods are not going to be in the Image class.

Change is the enemy of perfect design.

A problem with inheritance is that after we aggregate commonalities between different classes into a parent class, if we find an exception to this commonality we need to make big changes.

Composition is an alternative to this. This pattern means reusing code without inheritance - if there are 2 classes that want to reuse code, they simply use the code. In the example, this could be done by first removing the save and load methods from the Image class, meaning it now represents an image in memory. Now instead of inheritance, we can pass an instance of the Image class to access any methods from it. Now, we can do things like load a jpg image, draw to it, save as a bmp image.

Inheritance allows reusability by extending code in child classes, and abstraction by using parent classes.

Composition on the other hand allows reusability by using the types you want, and to allow for methods like save, load without caring about the subclasses via interfaces. Instead of a full parent class which details what an inheriting object will do (since it inherits all methods and attributes of the parent class), an interface is meant to define what an object can do. Interfaces are minimal and can be easily put onto existing classes compared to parent classes.

Passing interfaces of what you are about to use is called dependency injection.

Composition does create code repetition in interface implementations, and needing to initialize internal types. We also need to write a lot of wrapper methods like getSomething to get data from internal types.

Composition however makes it easy to adapt code to new requirements, and reduces coupling to re-used code (#DOUBT What does coupling to re-used code mean).

Emacs 29.4 (Org mode 9.6.15)