Design note: why EK9 favours composition over inheritance
This note goes with Composition in EK9, which asks why EK9 labours traits and composition so much. These are opinions, and you may think them incorrect, opinionated or extreme. EK9 has been driven partly by experience: of 'C' and structs, and of the joy and pain of object-oriented programming.
From structs to class hierarchies
When object-oriented programming started to gain ground, defining data structures ('structs' in C) and manipulating them with functions fell out of use. Object-oriented developers considered that a good thing, and classes and class hierarchies became the main driving force. The first classes were relatively simple to understand. Before long, very large and deep hierarchies were common, in many cases with multiple inheritance adding to the complexity.
The main reason the 'new OOP' approach was a good thing is that it hid data and limited access to state, specifically its mutation. EK9 gets that protection another way, with pure, and so can use records and functions again without the 'getters' that spread through OOP code bases.
How the rot set in
- Modelling 'real life'. Object-oriented programmers were taught to model real-life concepts. A Square 'is a' Rectangle mathematically, but that does not mean you can or should model it that way in a class structure.
- Inheritance for convenience. Wanting some of another class's functionality and getting it by inheritance produces massive interdependence and coupling.
- Protected fields. With protected fields/properties even encapsulation is lost.
- Java. Java classes were slightly simpler: no multiple inheritance, and interfaces that (originally) had only abstract methods. But inheritance was still the main mechanism developers used to add functionality, so hierarchies became quite deep.
Why composition was not used more
It was not made easy enough. Imagine a trait/interface with 20 methods, and a class that implements all 20. To compose that class with another that implements the same trait/interface, you write 20 methods that only call delegate.{methodName}.
EK9's by does that for you. A class can have several traits, and each trait, with all its methods, can be delegated to a concrete class that already exists. Override a few of those methods and EK9 does not delegate them. Delegation becomes as easy as inheritance, so you can choose it on its merits.
The composition example shows the result on a design that would otherwise need a class hierarchy with multiple inheritance.