Unwanted Gorillas

Unwanted GorillasA comparison between class inheritance and object compositionRanjit SaimbiBlockedUnblockFollowFollowingMay 7Photo by Ahmet Sali on UnsplashI.

Object Oriented Programming and InheritanceThe diagram below renders in neat form the ideal use case for inheritance: a collection of classes organised by domain, with a clearly defined hierarchy structure (from root to subclass).

Each subsequent subclass inherits its attributes and behaviours from the last in an additive fashion — the root defines universal functionality, and (as a general rule) each subsequent class layers its own attributes and behaviours on top, such that the most junior children in the hierarchy inherit a chain of functionality from their direct parents and ancestors.

A diagram illustrating class inheritance by Charles Scalfani, from Goodbye, Object Oriented ProgrammingES6 introduced the class () function, thereby aping in more explicit fashion the Object Oriented toolset familiar to users of OO languages.

The advantages of this approach are well established:Re-use — objects can be re-used across applications mitigating need for repetition.

Modularity — each object forms a separate entity whose internal workings are decoupled from other parts of the application.

Polymorphism — inherited methods can behave differently from object to object (again mitigating repetition and assisting with debugging).

Inheritance through reference is also memory efficient.

Simplicity — OOP provides a framework for semantic and conceptual organisation, and encourages the breaking down of complex requirements into discreet, abstracted and (most importantly) simple actions.

II.

The Gorilla / Banana ProblemIt would be remiss to characterise OOP as an inferior design methodology, or inherently limited.

It clearly has its advantages.

A more fair comment is that recent practice has started to throw-up certain limitations / pitfalls for which a compositional approach might be more appropriate.

Tool selection should be led by the problem at hand, not by attachment to any given tool.

Independent appraisal should be the driver behind design choice.

With that said, the below quote gives a flavour of the limitations of an approach that is over reliant on OO.

The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them.

You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.

— Joe Armstrong, Coders at WorkWhat does this mean in practice?Tight coupling — child classes are dependent on the implementation of the parent class.

Fragile base class — changes to the base class can have unintended consequences for descendant classes which can be extremely difficult to debug.

Inflexible hierarchies — given the complexity and unpredictability of real world modelling, class taxonomies eventually become inept for new use-cases.

Duplication by necessity — inflexible hierarchies force new use cases to be implemented by duplication, rather than extension, leading to similar classes which are unexpectedly divergent.

III.

CompositionThe compositional paradigm approaches object composition on the basis of what things do as opposed to what they are.

This provides a more flexible taxonomy of behaviours which isn’t as strictly bound as the hierarchical model.

In brief, a functional approach would first define the behaviours we wish to elicit across our various objects and abstract these for re-use.

For example, we have a root class Animal, which has Lion and Tiger subclasses.

Years later they mate and give birth to a Liger — from which parent does this creature inherit its behaviour?.Overlapping function calls and attributes would lead to some of the issues discussed above.

Rather, how about, in the first instance, we map out our function calls (eating, sleeping, playing, roaring, defecating… ) and each time we need to add a new animal to our roster, we assign it behaviours as needed.

function Liger(name, energy, breed) {let liger = { name, energy, breed, friends: [] }return Object.

assign( liger, eater(liger), sleeper(liger), player(liger), roarer(liger), defecater(liger), ) }IV.

ConclusionPhoto by 青 晨 on UnsplashThe above comparison isn’t about pitting methodologies against one another, but rather about the importance of actively appraising design approaches as one goes along.

In the interest of balance, why wouldn’t one wish to take a compositional approach?.Lack of readability (brought on by the increased abstraction of terms), the lower proliferation of practices and resources (vs.

OOP) and a steeper learning curve, are a few reasons.

It might be that the advantages of inheritance are more appropriate.

It’s a balancing act.

.. More details

Leave a Reply