Tuesday, March 18th, 2008

Subclassing and the prototype chain

Category: Dojo, JavaScript, Library

Are you sure you should be subclassing that? is the question that Neil Roberts asks.

He goes on to solve a problem: you just want to change ONE property in this class, but you can’t change it on the actual class because that value would now be used across all instances of that class. So in order to make it happen, you go through all the messy, painful steps described above.

But wouldn’t it be nice if we could just do this:

javascript

  1. var Child = sp.clone(Parent, { foo: "new value" });

He walks through the implementation, teaching you more and more about prototype based inheritance as you go. You have to go through the steps to really understand how he ends up with this:

javascript

  1. sp.clone = function(superclass, mixins){
  2.     var original = superclass.__original__ || superclass;
  3.     var f = function(){ original.apply(this, arguments); }
  4.     f.__original__ = superclass;
  5.  
  6.     var unchain = arguments[arguments.length-1] === true;
  7.     if(unchain){
  8.         f.prototype = dojo.mixin({}, superclass.prototype);
  9.     }else{
  10.         dojo.delegate(superclass.prototype);
  11.     }
  12.  
  13.     for(var i=1, arg, l=arguments.length-unchain, args=[f.prototype]; i<l ;>
  14.         arg = arguments[i];
  15.         args[i] = (typeof arg == "function") ? arg.prototype : arg;
  16.     }
  17.     dojo.mixin.apply(null, args);
  18.  
  19.     f.prototype.constructor = f;
  20.  
  21.     return f;
  22. }

Posted by Dion Almaer at 12:10 am
6 Comments

+++--
3.8 rating from 27 votes

6 Comments »

Comments feed TrackBack URI

There are a lot of errors in his examples, starting from anif else without assignment instead of a ternary:
f.prototype = unchain ?
dojo.mixin({}, superclass.prototype) :
dojo.delegate(superclass.prototype);

continuing with a loop that remove a boolean variable from an integer
arguments.length-unchain where unchain is arguments[arguments.length-1] === true

The goal of its code is more clear than code itself, but I wonder if it is a good OOP practice.

What I mean is that is not so common to need only one method for only one instance of that constructor … there’s something wrong in the constructor, that is missing one prototoype, or in instances … where every instance requires one different method.

Why in every other language we have not this kind of problem or, when we should have a similar one, we simply declare the class as dynamic and we attach a delegate as a property?

It seems that He’s using all this code to simply attach a method to a single instance?
var inst = new constructor;
// do you need a method only for this instance, uh?
inst.method = callback;
inst.method(do, whatever, stuff);

In my opinion, this is exactely the same, without overcode and without dojo requirement. dojo has some many features that use them for this basic task seems a bit excessive.
Regards

Comment by Andrea Giammarchi — March 18, 2008

@Andrea, as hard as it was to understand the error you were talking about, thanks for pointing it out, I’ll have it fixed.

This isn’t meant to solve the problem for a single instance. It’s meant to solve it for an entire class. It’s exactly what happens in something like your example at the end there, where you are creating instances, changing some properties, and then you notice that you change the same properties in 30 places in code. Most of the time, in that situation, people create a full subclass. I’m simply explaining that there’s a better solution.

There is absolutely no Dojo requirement for this code to work. The file at the end of the page is positively tiny, it implements all requirements, and contains everything you need to try the code out for yourself.

Comment by pottedmeat — March 18, 2008

So are you worried about references? If that’s the case.. it’s as simple as iteratively copying into a new object…

I should prob. read the article.

Comment by ibolmo — March 18, 2008

This idea is really old. I don’t know about support for this in popular libraries like Prototype, but I’ve been doing this in my own library (not released yet) since the beginning. Don’t see what’s so special or hard about it.

Comment by musicfreak — March 18, 2008

pottedmeat, what I mean is that if you need temporary a method, you can recycle them using call or apply and the instance as first argument, or set callback as property and simply use them as dynamic method.

On the other hand, if You need that a lot of instances requires a method that’s not in the constructor.prototype, there’s something wrong, and you have two choice: add that method in the prototype, or subclass the constructor, adding the prototype, with one of the 100 extend methods we have around the net (anyway, you know not every method is really good, and too many methods are not “so standards”, so your alternative could be another valid one).

Finally, sorry for the boolean mistake.
If we use a loose type language as JS is, 1 + true === 2 and 1 + false === 0 … anyway, I do not usually use boolean as a “bit” value, but it could be an implicit trick to avoid some var declaration. So sorry again, and thanks for the trick :D

Regards

Comment by Andrea Giammarchi — March 18, 2008

@Andrea, you said “you have two choice: add that method in the prototype, or subclass the constructor, adding the prototype”

Yes, and I actually say this in the opening paragraphs of this article. I know a number of toolkits offer this extend functionality, but many of them are structured around the inheritance chain, and I’m trying to get rid of that with that. Note that setting the unclean variable to true will create a full clone of a class, which I haven’t seen available in the toolkits.

Not just that, but the goal here is to teach about how to, as @ibolmo points out above, iteratively copy the stuff you need into a new object, and also how the prototype and protoype chain works. And it’s meant to do it all without requiring a toolkit.

Point is, it’s not about just creating a function, it’s about teaching people about the pitfalls of subclassing, and how to fix it. My function just shows the various things involved in fixing it.

Comment by pottedmeat — March 18, 2008

Leave a comment

You must be logged in to post a comment.