Classical composition

3 min readOct 23, 2015

I assume anyone reading this knows that the real evil is actually bad OOAD — where people are favoring inheritance (designing types after what they are) over composition (designing types after what they do), regardless of what techniques are used to achieve this (classical/prototypical inheritance, multiple inheritance, mixins, or stamps).

In case you have’t, please read different definitions of inheritance first before we move on.

Quoting Jeff M:
Yes, also, absolutely. Though, since Mattias makes the same mistakes as Elliott regarding composition and inheritance, I don’t think we should consider his video “awesome.” After all, the whole point of the video was to explain composition and inheritance, and he explains neither correctly.

First, let’s talk about mission. I believe that a greater mission both Eric Elliott and Mattias Petter Johansson had in mind is to make people a better programmer and succeed in their job and company.

That’s why I consider these articles and videos awesome and extremely valuable. We need better software and we need better programmers!

Especially I’m just a new grad, and did not yet get a chance to see projects fail again and again. Though I’ve seen a lot of my personal projects had come to a halt, Eric had seen real companies fail.

We humans like to stick with what we know.

Sometimes to break a bad habit (in this case, broken OOAD), you need to break yourself from anything that may afford that bad habit (in this case, classes).

Eric had taken that to quite an extreme level, and said that “you shouldn’t hire a developer who insists on using classical inheritance.”

If this advice is able to protect the company from most people who are doing broken OOAD, and in turn from bad software, and eventually, company failure, then why not!

Of course, some JavaScript and OOAD ninjas will be pissed off by this statement. Some people responded angrily (based on the responses to 10 Interview Questions Every JavaScript Developer Should Know). And Jeff M may be right that this kind of advice may cause more harm than good.

I myself have no opinion on this. I can only say that if you don’t hire a JavaScript ninja just because that person uses classical inheritance, you won’t know if that person may also be an OOAD ninja.

Anyway, I’d like to thank Eric Elliott, Jeff M, Mattias Petter Johansson, and everyone else involved for all these resources and (quite heated) conversations. I wouldn’t have figured them out if this hadn’t started in the first place.

Classical composition

Now for today’s show: I will do object composition (simulating multiple inheritance) by means of classical inheritance, using ES6 class!

Remember Mattias’s example, the MurderRobotDog?

First, we’ll define the base functionalities based on what these our set of objects can do.

I’ll define them using higher-order classes, just like higher-order components:

const Pooping = Base => class Pooper extends Base {
poop() { console.log('I poop.') }
}
const Barking = Base => class Barker extends Base {
bark() { console.log('I bark.') }
}
const Meowing = Base => class Meower extends Base {
meow() { console.log('meow meow meow meow meow.') }
}
const Driving = Base => class Driver extends Base {
drive() { console.log('I drive.') }
}
const Cleaning = Base => class Cleaner extends Base {
clean() { console.log('I clean.') }
}
const Murdering = Base => class Murderer extends Base {
kill() { console.log('I kill.') }
}

Now you create the concrete classes. See how clean it is:

class Dog extends Barking(Pooping(Object)) { }class Cat extends Meowing(Pooping(Object)) { }class CleaningRobot extends Cleaning(Driving(Object)) { }class MurderRobot extends Murdering(Driving(Object)) { }class MurderRobotDog extends Murdering(Driving(Barking(Object))) { }

And now, you have yourself a MurderRobotDog, implemented using classical inheritance with ES6 classes, without any banana-gorilla problem!

Without any factory function, Object.create, or Object.assign either! (Actually I lied, these so-called higher-order classes turn out to be an instance of factory functions, which happens to create classes.)

Use it just like any other classes:

let bolt = new MurderRobotDog// I can do these
bolt.kill() // => I kill
bolt.bark() // => I bark
bolt.drive() // => I drive
// But I don’t poop!
bolt.poop() // => bolt.poop is not a function
// Sorry, but if I don't know `instanceof` intimately,
// I’d say `instanceof` still lies.

console.log(bolt instanceof Murdering) // => false
// Don’t use instanceof! Use duck typing!
console.log(!!bolt.kill) // => true

This is one of the awesome things you can do in JavaScript, possible because of the dynamic nature of JavaScript.

I love JavaScript!

--

--

Thai Pangsakulyanont
Thai Pangsakulyanont

Written by Thai Pangsakulyanont

(@dtinth) A software engineer and frontend enthusiast. A Christian. A JavaScript musician. A Ruby and Vim lover.

Responses (5)