The Heart & Soul of Prototypal OO: Concatenative Inheritance

Eric Elliott
JavaScript Scene
Published in
7 min readJan 25, 2016

--

What do jQuery, Underscore, Lodash, and the ES6 `Object` utilities have in common?

  1. They are the most commonly used utility libraries in the JavaScript world.
  2. They all contain a utility that serves the purpose of concatenative inheritance.

I recently wrote an article called “Master the JavaScript Interview: What’s the Difference Between Class and Prototypal Inheritance?”

Afterwards, I got several questions asking for more information about concatenative inheritance. Because concatenative inheritance is the heart and soul of prototypal OO in JavaScript, and because we use it so heavily, I think it’s critical that we as a community develop a deeper understanding of it.

Concatenative inheritance is the most commonly used inheritance technique you’ve never heard of. Let me preempt some questions:

  • Yes, it’s a thing.
  • No, it’s not an obscure technique. Read on for citations of very common idioms and examples. You’ve probably used it 1,000 times and just didn’t know it’s called “concatenative inheritance”.

In JS, the essence of concatenative inheritance is often masked by the common name “mixins”. Confusingly, “mixins” have other meanings in other languages, and even in some JavaScript libraries. It also has uses that would be confusing to call “mixins”. Because of those reasons, I prefer the more precise term “concatenative inheritance”.

“Concatenative inheritance is the heart and soul of prototypal OO.”

What is Concatenative Inheritance?

Concatenative inheritance is the process of combining the properties of one or more source objects into a new destination object. Believe it or not, it is the most commonly used form of inheritance in JavaScript.

Defaults/Overrides (>= ES5)

It is frequently used in common JavaScript idioms including the ES5 version of the defaults/overrides pattern (note that “mixins” would be a confusing name for this use-case):

You can see examples of the ES5 defaults/overrides pattern in many thousands of jQuery plugins, where `$.extend()` originally gained popularity in between 2006–2010.

Of course, defaults/overrides is extremely common outside the jQuery world, as well. ES6 introduced parameter defaults, which is quickly replacing this pattern today.

Side note: jQuery is still the most widely used JavaScript library by a HUGE margin, and its popularity is still growing in spite of the much improved compatibility of various DOM implementations, and the rise of alternative DOM abstractions such as React.

Object Composition

Concatenative inheritance is the easiest way to achieve JavaScript’s simplified form of object composition (this is what most people mean by “mixins” in JavaScript):

This composition pattern started to gain mainstream use and popularity with Underscore in 2010, with wide adoption of the `Backbone.Events` mixin from the Backbone documentation:

Two Foundational Kinds of Prototypal Inheritance

In “What’s the Difference Between Class and Prototypal Inheritance?” I defined prototypal inheritance like this:

Prototypal Inheritance: A prototype is a working object instance. Objects inherit directly from other objects.

That definition can be achieved with two different mechanisms in JavaScript, again from the same article:

Prototype delegation: In JavaScript, an object may have a link to a prototype for delegation. If a property is not found on the object, the lookup is delegated to the delegate prototype, which may have a link to its own delegate prototype, and so on up the chain until you arrive at`Object.prototype`, which is the root delegate. This is the prototype that gets hooked up when you attach to a `Constructor.prototype` and instantiate with`new`. You can also use `Object.create()` for this purpose, and even mix this technique with concatenation in order to flatten multiple prototypes to a single delegate, or extend the object instance after creation.

Concatenative inheritance: The process of inheriting features directly from one object to another by copying the source objects properties. In JavaScript, source prototypes are commonly referred to as mixins. Since ES6, this feature has a convenience utility in JavaScript called `Object.assign()`. Prior to ES6, this was commonly done with Underscore/Lodash’s `.extend()`jQuery’s `$.extend()`, and so on… The composition example above uses concatenative inheritance.

For those who’ve never heard of this, some background:

History of Concatenative Inheritance

Both copy and delegate mechanisms are recognized in the often-cited “Treaty of Orlando” which describes different approaches to object-oriented code reuse:

Empathy: The ability of one object to share the behavior of another object without explicit redefinition.

Template: The ability to create a new object based on a template, a “cookie-cutter” which guarantees, at least in part, characteristics of the newly created object.

[The summary expands on templates:] Templates allow two objects to share a common form. They may be embedded inside classes, or they may be objects themselves.

A little translation is needed here. Essentially, they’re saying that the primary mechanisms of inheritance are:

  1. The ability to “share the behavior”, or delegate property lookup from the target object to some already existing object properties, aka prototype delegation.
  2. The ability to create new instances based on pre-defined behavior, as in the ability to share behavior by creating a non-referenced copy of the behavior which then becomes instance safe.

In class-based environments, you can use the delegate pattern from “Design Patterns: Elements of Reusable Object Oriented Software” (for delegation), and classes (for templates) to achieve these aims.

In JavaScript, empathy is built-in as prototype delegation. we don’t need `class` to get new objects and instance safety because we can simply copy an exiting object. In other words, you can use an existing object as a template.

So, in JavaScript:

  • Empathy is accomplished with delegate prototypes.
  • Templates are accomplished by copying from existing objects, sometimes called exemplar prototypes.

You can also dynamically extend an existing object, which leads us down the road toward concatenation as an inheritance mechanism…

The Treaty of Orlando describes what we now refer to as dynamic object extension in the section on “minimal templates”:

“…a minimal template is a cookie cutter in the same sense, but once created, cookie-cut objects can define other attributes as well. An extended instance — one generated by a minimal template, then added to — does not, a priori, have a template for its type. It’s descendants cannot be strict instances, since there is a no template for their type.”

This describes the idea that objects can be built by adding properties to existing instances ad-hoc: Dynamic object extension, which is the foundation of concatenative inheritance.

“Dynamic object extension […] the foundation of concatenative inheritance.”

In the book “The Interpretation of Object Oriented Languages” by Iain Craig (if you hunt this down, I recommend the first edition — later editions introduced lots of confusing typographic errors) describes concatenative inheritance used in combination with delegates in prototype-based Kevo language, which has become the canonical language reference for the origins of the phrase, “concatenative inheritance”:

“Every Kevo object can be considered a complete set of all the properties associated with its parent objects. This means that Kevo objects are entirely self-contained and no parent relation is required to express inter-object derivation relationships.”

“Kevo objects […] can be created anew by the specification of slots and methods. Alternatively, they can be created by cloning and modification.”

It’s hard to find usable Kevo examples. Kevo’s use of concatenative inheritance is known and widely referenced in OO design academic circles because of the prototypal OO research work and academic papers published by its inventor, Dr. Antero Taivalsaari. He has also written about concatenative inheritance in JavaScript. Incidentally, Dr. Taivalsaari is best known for his work on the design of Java ME, which is used in billions of devices.

The Self Connection

Prototypal inheritance made its way into JavaScript by way of influence from Self. Like JavaScript, Self supports:

  • Delegation
  • Composition of Multiple Ancestors
  • Dynamic object extension

“The design of inheritance and encapsulation in Self, an object-oriented language based on prototypes, results from understanding that inheritance allows parents to be shared parts of their children.”

Some of the Self papers that influenced JavaScript’s design can be found online. They make for a very interesting read. (Note that Self’s “slots” are analogous to JavaScript’s “properties”.)

Concatenative Inheritance: The Most Commonly Used Inheritance You’ve Never Heard Of

Because dynamic object extension is so common in JavaScript, and so fundamental to so many common JavaScript idioms, it is the most commonly used form of inheritance in JavaScript. It is not widely recognized as such because it is not what people think of when they think of the word, “inheritance”.

People have developed a very strong association between the word “inheritance” and “class inheritance” — so much so that they don’t recognize any other form of inheritance: even if it’s more commonly used.

Concatenative inheritance is so common and so simple, people do it every day without even realizing it.

See the proliferation of facilitating utilities in all of the most-frequently used utility libraries: `jQuery.extend()`, `underscore.extend()`, `lodash.assign()`, and now the built-in `Object.assign()` for evidence of widespread use.

Keep an Open Mind About Inheritance

If you arbitrarily restrict your understanding of language terms too much to a narrow definition, you often blind yourself to a more broadly usable understanding which can be effectively applied to a wider range of problems, and often to much simpler solutions to your existing problem.

Eric Elliott is the author of “Programming JavaScript Applications” (O’Reilly), and “Learn JavaScript Universal App Development with Node, ES6, & React”. He has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more.

He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.

--

--