Saturday, May 5, 2012

Javascript OOP - Multiple Inheritance

Multiple inheritance is a behavior when a single class extends the functionality of multiple parent classes. For example, an alarm-clock has the properties of both a clock and an alarm. The desired situation is that the parent classes handle the distinct behaviors without needing to know about each other. For an alarm-clock, this means that the clock class will track time, the alarm class would make an alarm action, and the alarm-clock class would allow different events to be set at specific times of the clock.

Many OOP languages support multiple inheritance either directly (C++) or through some other mechanism (Java Interfaces, Objective-C Protocols). How can this be implement in JavaScript. Enter jQuery.

jQuery has this baller function, $.extend. It receives n arguments ( $.extend(arg0, arg1, …., argN); ) and all the members of argN are copied to arg(N-1), then from arg(N-1) to arg(N-2), and so on down the line. This is perfect for creating options for jQuery parameters. However, it can also be used to implement Multiple Inheritance for javascript objects.

Lets check out a very simple, snarky alarm clock.

//create parent Alarm
Alarm = function(){};
//with one instance method
Alarm.prototype.ring = function(){
     console.log("AAAAAHHHHHHHH");
}

//create parent Clock
Clock = function(){};
//with one instance method
Clock.prototype.time = function(){
     console.log("is an illusion");
}

//create child
AlarmClock = function(){};
//inherit from A and B
AlarmClock.prototype = $.extend(new Clock(), new Alarm()); // BOOM!

c = new AlarmClock();
c.ring();//AAAAAHHHHHHHH
c.time();//is an illusion

Pretty cool. However, multiple inheritance presents situations that single inheritance doesn't. What happens if parent classes contain identically named methods? In $.extend the right hand parameter overrides the one to its left. So, if ClassA and ClassB have identically named methods, then ClassB's will override ClassA's.

Lets see this in action.

//create parent with cry
Human = function(){};
Human.prototype.cry = function(){
     console.log("OUCH!!!");
}

//create another parent, also with cry
SpaceMarine = function(){};
SpaceMarine.prototype.cry = function(){
     console.log("FOR THE EMPEROR!");
};

//inherit from both parents
Character = function(){};
Character.prototype = $.extend(new Human(), new SpaceMarine()); // BOOM!
c = new Character();
c. cry(); //FOR THE EMPEROR!
//cry is inherited from SpaceMarine

Multiple inheritance also evokes an interesting question for object type. What is the object type of ClassC? In this case only the leftmost parent class passes on its type.

ClassC = function(){};
ClassC.prototype = $.extend(new ClassA(), new ClassB()); // BOOM!
var c = new ClassC();
console.log(c instanceof ClassA); //true
console.log(c instanceof ClassB); //false

This technique requires some function to duplicate properties and methods from object to object. I use jQuery.extend, because I use jQuery it on most projects, but there could be alternatives out there, and it would be simple to create a  rudimentary replacement.

Multiple inheritance is especially useful with protocols. For example, a single class to provide data for and respond to interaction with a datalist, ala UIKit's UITableViewDataSource and UITableViewDelegate. To allow a single object to perform two distinct tasks, some form of multiple inheritance must be used.

2 comments: