jashkenas/coffee-script — Issue #1762: Class system extendability - A simple solution
Author: soniciq
Created: 2011-10-10 18:34:45+00:00
State: open

Hi,

The one thing keeping me from using CoffeeScript full-time is that it's class system cannot be extended in any way. Below is an idea that allows users to hook into the class system, it's very similar to that in Ruby and Spine.js.

I am suggesting that the following coffee script:

```coffeescript
class Bar

class Foo extends Bar
myInstanceMethod: -> console.log 'I am an instance method';
@myClassMethod: -> console.log 'I am a class method';
```

Should generate:

```javascript
var Bar, Foo;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
var mixin = function(target, obj) {
for (var key in obj) { if (__hasProp.call(obj, key)) target[key] = obj[key]; } };
mixin(child, parent);
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
child.include = child.include || function(obj) { mixin(this.prototype, obj); };
child.extend = child.extend || function(obj) { mixin(this, obj); };
return child;
};
Bar = (function() {
function Bar() {}
return Bar;
})();
Foo = (function() {
__extends(Foo, Bar);
function Foo() {
Foo.__super__.constructor.apply(this, arguments);
}
Foo.include({
myInstanceMethod: function() {
return console.log('I am an instance method');
}
});
Foo.extend({
myClassMethod: function() {
return console.log('I am a class method');
}
});
return Foo;
})();
```

This way, should Bar want to hook into the class system it could do the following:

```coffeescript
class Bar
@include: (obj) ->
console.log "About to declare: '#{key}' on proto" for key in obj
super

@extend: (obj) ->
console.log "About to declare: '#{key}' on class" for key in obj
super

class Foo extends Bar
myInstanceMethod: -> console.log 'I am an instance method';
@myClassMethod: -> console.log 'I am a class method';
```

I think this would make CoffeeScript's class system truly powerful and allow things like Ext's preprocessors... the applications are endless. The other benefit of this is that the resulting minified JS would be smaller due to the object notation used in `include` and `extend`. Obviously the `include` and `extend` function names are just a suggestion but I think the likeness to Ruby is a good thing. To avoid conflicts with existing code, they could always be `__include` and `__exclude`.

This tiny change also introduces Ruby-esque 'Modules' e.g.

```coffeescript
CommonInstanceMethods =
sharedFunction -> console.log 'I come from CommonInstanceMethods'

CommonClassMethods =
sharedFunction -> console.log 'I come from CommonClassMethods'

class Foo
@include CommonInstanceMethods
@extend CommonClassMethods

class Bar
@include CommonInstanceMethods
@extend CommonClassMethods
```

I would create a patch but don't know enough about parsers to be able to implement it. I really hope we can add this as currently there is no way to extend the class system.

Thanks,

Jamie