Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

I believe there is a bug in your object model for handling super. I have tested it and it does indeed work incorrectly (although not in the way I expected it to work incorrectly). Basically, your super calls only work if your class tree is 1 level deep. As soon as you have something like Animal -> Horse -> BigHorse, then it breaks down. This is because super() gets translated to:

this.constructor.prototype.NAME.call(this, args)

So, if we had move on BigHorse, Horse, and Animal, BigHorse would call super (resulting in Horse's implementation being called), but then Horse calls super which again calls Horse's implementation, since this.constructor.prototype still points to Horse.prototype. Thus, you can't continue climbing up the chain. When I tried it though, it seemed to just skip the intermediate classes and go down to the base class, which is of course equally broken. We used to have the same problem a long time ago in Objective-J. The fix is pretty simple, you should just inline the actual class name when dealing with supers:

Horse.prototype.NAME.call(this, args), which then calls: Animal.prototype.NAME.call(this, args)

Hope I avoided you some pain with that one. I remember 3 years ago not understanding why on earth my code was broken and thinking it was algorithmic for the longest time until I realized the entire underlying parts were broken.



Thanks for that. You're absolutely right -- the javascript dynamically-scoped "this" keyword strikes again. I've fixed it in the last commit, by using prototype.__proto__, and adding an "extends" keyword for convenience. You can see it in action here:

http://jashkenas.github.com/coffee-script/#inheritance

It's out with version 0.1.2 now.


It seems you should use "Horse extends Animal.prototype" in your examples or just make "Horse extends Animal" compile to "Horse.prototype.__proto__ = Animal.prototype". Also a subclass constructor should call the one of the superclass. Otherwise, a single Animal instance is shared by all subclass instances and for no reason Animal is created simply to declare a subclass.


Be careful with __proto__, it's non-standard and will break in some engines.


To get the equivalent of __proto__ that works in every engine see goog.inherits from Closure.


Thanks for the pointer. I've pushed a commit that avoids __proto__, and produces this...

CoffeeScript:

    Horse extends Animal
JavaScript:

    Horse.__superClass__ = Animal.prototype;
    Horse.prototype = new Animal();
    Horse.prototype.constructor = Horse;
Calling super uses the __superClass__ reference. I hate to add it as an enumerable property, but there doesn't seem to be any other way to get at it, and at least it's on the class and not the object.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: