Ruby : Composition over Inheritance because The Force is Strong with Composition

Kartik Jagdale
Jan 12, 2017 · 5 min read
The Force is Strong with Composition

Recently I came across a programming convention called composition which is nowadays a preferable choice among developers over inheritance and in this article I would like to explore this convention using a small interactive funny example. Let’s begin.

So, here we are creating an enterprise-grade software for our client who demands to create a game which imitates the functions of a Man.

Pretty Simple demand huh…. And in a split of seconds, we create a Man class

# Class Man with functions eat, sleep, poop, lol
Class Man
.eat()
.sleep()
.poop()

We show this to our client and he is pretty impressed with our ability and speed of execution. Good Work he says.

But you should know with compliments come hidden demands.(evil smiley)

He wants us to add Dog to the game and make the man speak and dog bark.

We do it and this how our code looks like

Class Man
.eat()
.sleep()
.poop()
.speak()
Class Dog
.eat()
.sleep()
.poop()
.bark()

We Show this to our client and he is happy and impressed but we are not because of all the repetition in the code and when we started our journey to programming, we have taken this sacred oath to keep our code DRY. So, we start thinking and go back to school where we learned inheritance.(the awww moment).

We decide to clean up the code and make it DRY by introducing an Animal Class and making Dog and Man class inherit Animal. So, all the common code goes to Base/Parent class Animal. Smart huh… Now, this is how our code looks like:

Class Animal
.eat()
.poop()
Class Man < Animal
.speak()
Class Dog < Animal
.bark()

Now, we are happy and our client is happy. Days pass by and one day our client come to us all excited and jumping to tell us his new brilliant idea. :D

He wants us to introduce a Cleaning Robot who will roam around and clean all the poop done by Man and Dog. And We do it in a split of a second.

Class CleaningRobot
.roam_around()
.clean()
Class Animal
.eat()
.speak()
.poop()
Class Man < Animal
.speak()
Class Dog < Animal
.bark()

Again, Everyone is happy and yet another requirement pops in (sighhhh). A Barking Dog Robot who will roam around and bark at Animals who try to poop in public places. This time we are now a professional programmer and we learn from our past mistakes and So, we follow inheritance in the first place and implement our logic for Barking Dog Robot by inheriting a Parent Class Robot in it. This is how our code looks like now:

Class Robot
.roam_around()
Class BarkingDogRobot < Robot
.bark()
Class CleaningRobot < Robot
.clean()
#----------------------------------------------------------Class Animal
.eat()
.poop()
Class Man < Animal
.speak()
Class Dog < Animal
.bark()

We give one look at a code and being a smart and experienced programmer we immediately sense a red flag in the code and can see future consequences if we keep following this pattern.

The bark() method is common in class BarkingDogRobot and Dog and somehow nothing fits in and if you remember we have taken an oath to keep our code Dry which keeps us bothering. :(

We can create a GameObject above all the classes something like below

Class GameObject
.bark()
Class Animal < GameObject
Class Robot < GameObject

But, But, But… it doesn’t have that magic charm and our code looks ugly. :(

And if we follow above example, then sometimes even a Man can bark.. lol

# Wtf.....
Man.new().bark() # Success

We keep going on…. keeping our client happy and also trying to stick to our oath by giving an entirely new imaginary meaning to DRY Convention and making our code uglier and uglier until one day we want to quit and go back to farming. lol…. END OF THE STORY COZ ONCE WRITTEN IS WRITTEN.

Composition to the Rescue

Inheritance is useful and I am not saying it’s entirely bad, but anything used extensively without thinking, Is.

The story ended above but, the entire above scenario would have been different if we have used composition instead. So, rather explaining what composition is, let’s code directly.

class Poop
.call()
class Bark
.call()
class Clean
.call()
# .... And So, On converting every action into Class Objectclass Man
#...
# Other Actions
# ...
def poop()
eat = Poop.new()
eat.call()
end
endclass Dog
#...
# Other Actions
# ...
def bark()
bark = Bark.new()
bark.call()
end
end
class CleaningRobot
#... other Actions
def clean()
clean = Clean.new()
clean.call()
end
end
class BarkingRobotDog
#...
# Other Actions
# ...
def bark()
bark = Bark.new()
bark.call()
end
end

Note: I know I should have used dependency injection instead of directly instantiating action class in methods without the consent of noun class, but that’s an entirely different topic.

So, what we have done here is, We’re now composing a bark and other properties when we need it, as opposed to expecting one from a parent class.

The Advantage here is that

  1. We can dynamically plug-in whichever class we see fit at runtime.

2. Types Man, Dog, BarkingRobotDog, etc.. do not have to conform to the interface of their previous parent. This could be a good thing because sometimes a change to the superclass can have serious effects on the subclasses.

3. And of course, we saved a Man from becoming a Dog. :p


Common Myth about Composition among ruby programmers :

Now Some Ruby people might say creating a class seems weird and same can have been implemented using a module and they name it as composition.

Something like below and I have seen many blogs referring use of modules as composition. However I can be wrong too and If you think I am, please guide me.

# Wrong implementation of composition as per my thinking.
module actions
.eat()
.sleep()
.bark()
.poop()
class Dog
include actions
class Man
include actions
class BarkingRobotDog
include actions

I think above quote easily explains what I think.

How to Decide: Composition or Inheritance?

Lots of developers would say that you should prefer composition over inheritance. And also while designing a system you should think in terms of is_a and has_a relationship.

When something is in a is_a relationship then you should use inheritance and When something is in a has_a relationship then you should go for composition.

My Views(which most people don’t care) on when to use inheritance and composition:

On Contrary to above hybrid model of designing a system, I am a bit on an extremist side. I think that is_a and has_a relationship can be misinterpreted by many people. Something like below:

A Person is_a Manager
A person has_a role of Manager

I think that we should favor one over the other entirely and follow it throughout the system. Currently, Composition seems to be at upper hand and I think we should follow composition entirely throughout the system.

You, on the other hand, have a free will and are welcomed to prefer whatever you want. lol….

Conclusion:

So, In this article, we saw how inheritance is a dark forest of evil and at the center of the forest sits the Evil Queen Multiple Inheritance who likes to eat programmers and how Composition is a Hero and can come to our rescue.

Happy Coding!!!

Signup for our Angular 2 fundamentals course

Reference :

  1. https://youtu.be/wfMtDGfHWpA(Mattias Petter Johansson)
  2. https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)
  3. https://en.wikipedia.org/wiki/Object_composition
  4. https://en.wikipedia.org/wiki/Composition_over_inheritance

Aviabird

Aviabird Technologies provides enterprise software consulting in Angular, Rails, Elixir, Golang, React, Flutter and other technologies.

Kartik Jagdale

Written by

Aviabird

Aviabird

Aviabird Technologies provides enterprise software consulting in Angular, Rails, Elixir, Golang, React, Flutter and other technologies.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade