In this article, I will explain what is concatenative inheritance and how we can use it to our advantage exactly like I use it at work and in Bliz, my open source web server framework for node.js, to build stable, fast, readable and testable applications.

What is concatenative inheritance?

As explained by the Javascript guru, Eric Elliott here — Concatenative inheritance is the process of combining the properties of one or more source objects into a new destination object.

Why do we need it?

If you have ever written a large application with Javascript, you already know it is a dynamic, weakly typed, prototype-based and multi-paradigm language, which on one hand gives you the power to write your applications however you desire, but, on the other hand, could create a mess.

For example, you write with es5 function constructors or es6 class declarations(which are the same old function constructors behind the scenes, the only difference is that they do not get hoisted), you have to deal with this and new keywords, which are a pain on their own. And what if your boss comes up to you and asks for a new feature, which consists of methods, each of which is written in a different class ? You won’t start inheriting 20 classes just to get a few methods, won’t you? The solution is to build our applications from composable objects and leverage Javascript Closures and functions as first class citizens to our advantage.

How

Let’s see how we can take advantage of the nature of concatenative inheritance.

getter factory function

Lets break our GetterFactory down:

It is a function It is a factory function, because it returns a new object The factory function expects some kind of dataObject The object returned has a method attached to it The method expects some sort of key The method itself looks for that key on our initial dataObject, which is available, thanks to closures.

Great, now that we understand what is going on, lets think. We have a function that when called, returns an object with a method on it. Maybe, if we combine a lot of these functions we can create something useful.

Let’s see another factory function:

setter factory function

This one looks the same as the previous one. We have a function that returns a new object with a method on it and takes use of its closure to modify an object. Awsome.

Lets combine the latter factories to an object.

example of object composition

Lets imagine our _data is private for a second. We declare a new variable called instance and assign a new object to it. We add the GetterFactory function to it and we pass our data object, we do the same with the SetterFactory . Remember each of these returns an object with a method on it? Great! Let’s console.log the instance to see what is going on.

output of console.log(instance)

We get a simple object with a get and a set functions, which are the results of calling the factories and combining them together. Now, lets try to get a variable and set a variable.

getting a variable

Our output looks like this:

output of getting a key

Our get function retrieved our key and printed it, just like we told it to in the beginning, great!

Lets set a key just to be sure it works

We set the key version to 2.0.0 and immediately ask for it.

Lets see the output

checking the set value

Now your thinking, this looks great, Yuri, but the _data is not really private.

I will show you how we can implement an InstanceFactory function, which combines all our factories and private data to an object.

InstanceFactory

Lets break this function down just so we can understand it better:

We have a function which expects an initialData argument and we use the rest operator for all other arguments and we put it inside the deps variable. We create an instance object inside the function. We assign what was passed in the initialData object to our _data variable, notice that object.assign does a shallow copy, so use deep copy if you need a completely new object, We reduce our deps variable to an object, which we can use to assign to our _instance variable and return it. The reduce function runs on all factories, calls them with a variable and adds them to the reduce object. Notice we did a switch case, that’s because if our factory name is getter or setter, we provide it with our _data variable, which is private by now, we do this so that all other factory functions would have to use our get and set methods to access the data. We pass the instance itself to all other factory functions that are not getter and setter to allow calling methods from the method itself.

Lets see how we make use of the InstanceFactory

Notice, it looks the same as the first object assign to our getter and setter function, only this time our first variable is our data which will get shallow copied and will be private.

Lets see the output of the console log:

What we have is a simple object with private data which can only be accessed through our get and set functions.

Now, lets go back to when our boss asked us to add a new feature to our application, he wants a killer robot dog which has 3 methods: Kill, Bark and Clean. Also, he wants to increment a counter every time our strange looking murder robot dog does something.

Let’s implement our bosses strange feature.

bark factory

Here we have our bark factory, which returns an object with bark method on it. Some of you are probably asking, how come we have the instance itself?

Lets go back to our InstanceFactory again:

See where the default case falls? whenever our factory is not a getter and a setter it will receive our instance which by the time you invoke some method, will have all other methods already on it.

That is why we can use the get and set methods inside bark. Now, lets add it to our instance.

We added our counter to our data object and added our bark factory as an argument.

Now, lets try barking and see our counter go up.

Great, we woofed and the counter went up.

Following this concept is now simple, for the other 2 methods, we simply create their factories and add them as arguments to our main InstanceFactory.

Our 3 factories

By now, you understand what is going on. Now, connect everything:

our main instance

Our output:

methods on our instance

Awsome, all of our methods are in place. We can now write unit tests for each factory and integration tests for a combination of factories, we can add features quickly and we do not need to worry about scoping anymore. This type of writing encourages us to build modular, stable and human readable applications.

Recap

We saw what concatenative inheritance means, we implemented our first factories and saw how to assign them to a simple object. Later, we introduced our scary InstanceFactory, which quickly became not so scary and very helpful. By the end we implemented our bosses strange feature request in no time.

Final Notes

Everything we wrote can be found here. Thanks a lot for reading and stay tuned for more of my thoughts on programming, architecture, design patterns, languages and more. Also, take a look here if you need a declarative graphql/realtime/http web server. I will be glad for code contributions.

Until next time!