Classical Vs prototypal inheritance

There are lots of problems with classical inheritance that don’t exist with prototypal inheritance, such as:

Classical Inheritance

Tight coupling. Inheritance is the tightest coupling available in OO design. Descendant classes have an intimate knowledge of their ancestor classes.

Inflexible hierarchies (aka duplication by necessity). Single parent hierarchies are rarely capable of describing all possible use cases. Eventually, all hierarchies are “wrong” for new uses — a problem that necessitates code duplication.

Multiple inheritance is complicated. It’s often desirable to inherit from more than one parent. That process is inordinately complex and its implementation is inconsistent with the process for single inheritance, which makes it harder to read and understand.

Brittle architecture. Because of tight coupling, it’s often difficult to refactor a class with the “wrong” design, because much existing functionality depends on the existing design.

The Gorilla / Banana problem. Often there are parts of the parent that you don’t want to inherit. Subclassing allows you to override properties from the parent, but it doesn’t allow you to select which properties you want to inherit.

Prototypal Inheritance

To understand how prototypal inheritance solves these problems, you should first understand that there are two different types of prototypal inheritance. JavaScript supports both:

Delegation. If a property is not found on an instance, it is searched for on the instance’s prototype. This enables you to share methods among many instances, giving you the flyweight pattern for free.

Concatenation. The ability to dynamically add properties to an object enables you to freely copy any properties from one object to another, all together, or selectively.

You can combine both forms of prototypal inheritance to achieve a very flexible system of code reuse. So flexible in fact, that it’s trivial to implement classical inheritance with prototypes. The reverse is not true.

Prototypal inheritance allows most of the important features you’ll find in classical languages. In JavaScript, closures and factory functions allow you to implement private state, and functional inheritance can be easily combined with prototypes in order to add mixins that support data privacy, as well.

Some advantages of prototypal inheritance:

Loose coupling. An instance never has a need to make a direct reference to a parent class or prototype. It’s possible to store a reference to an object’s prototype, but it’s ill advised, because that would promote tight coupling in the object hierarchy — one of the biggest pitfalls of classical inheritance.

Flat hierarchies. It’s trivial with prototypal OO to keep inheritance hierarchies flat – using concatenation and delegation, you can have a single level of object delegation and a single instance, with no references to parent classes.

Trivial multiple inheritance. Inheriting from multiple ancestors is as easy as combining properties from multiple prototypes using concatenation to form a new object, or a new delegate for a new object.

Flexible architecture. Since you can inherit selectively with prototypal OO, you don’t have to worry about the “wrong design” problem. A new class can inherit any combination of properties from any combination of source objects. Due to the ease of hierarchy flattening, a change in one place doesn’t necessarily cause ripples throughout a long chain of descendant objects.

No more gorillas. Selective inheritance eliminates the gorilla banana problem.

I am not aware of any advantage that classical inheritance has over prototypal inheritance. If anybody is aware of any, please enlighten me.

Leave a Comment