jashkenas / coffeescript

Unfancy JavaScript
https://coffeescript.org/
MIT License
16.51k stars 1.99k forks source link

Executable class bodies, static inheritance, metaproggin'... #841

Closed jashkenas closed 12 years ago

jashkenas commented 14 years ago

There's an executable branch over yonder:

https://github.com/jashkenas/coffee-script/tree/executable

And if you're feeling brave, I'd recommend checking it out.

It pulls in parts of satyr's coco patch for executable class bodies, and tweaks some things. This means that:

A few examples... A regular class now looks like this:

class Animal
  (name) -> 
    @name = "Mr. " + name

  run: (distance) ->
    ...

Since it's arbitrary code, you can conditionally define methods.

class Logger
  if env is 'development'
    log: (err) -> console.log err
  else if env is 'production'
    log: (err) -> console.error err

What does that compile into, you may ask...

Logger = function() {
  function Logger() {}
  if (env === 'development') {
    Logger.prototype.log = function(err) {
      return console.log(err);
    };
  } else if (env === 'production') {
    Logger.prototype.log = function(err) {
      return console.error(err);
    };
  }
  return Logger;
}();

And finally, let's rustle up some metaprogramming. The following is part of a test case on executable. The idea is to create a base class that provides a simple way to define attributes, creating a function that serves as a getter and a setter for the private storage of a value.

class Model
  @attr = (name) ->
    this.prototype.[name] = (val) ->
      if val?
        @["_" + name] = val
      else
        @["_" + name]

class Robot extends Model
  @attr 'power'
  @attr 'speed'

robby = new Robot

ok robby.power() is undefined

robby.power 11
robby.speed Infinity

eq robby.power(), 11
eq robby.speed(), Infinity

What do y'all think about this proposal?

michaelficarra commented 14 years ago

Besides a few typos (log: (err) -> log = (err), this.prototype.[name] -> @prototype[name]), I think this is a great path to continue pursuing.

That said, I have my concerns.

  1. The proposed syntax does not allow "local" functions / variables, functions / variables that are wrapped in the defining closure and accessible only to those methods defined on the class at compile time. I understand that this can be done by wrapping the entire class definition in a function that returns the class, but is that really something we want to make users of coffeescript do? The syntax I proposed in the last thread about this (I don't mean to say this is the best or anything, I'm just most familiar with the one I wrote) handles this by defining instance methods with @ and class/static methods with @@, as they are referenced in ruby.
  2. The second problem I had with this proposal is the outputted JS. But we can talk about this more once the defining syntax is more concrete.
  3. Are semantics defined for entering code into the body of the constructor, eg an initialize method? There is also an attempt to remedy this in my old proposal.

In any case, even if the community does come to an agreement on the semantics and syntax of this new feature, I want to stress early on that we should really give this one a good amount of time in hardening before merging it onto master. We've seen how big changes like this getting pushed through too fast can harm the community and I don't want it to happen again, no matter how much I am in favor of this change.

jashkenas commented 14 years ago

1) The syntax does allow for local (private) methods.

class Person
  privateFunc = ->
  publicFunc: ->

Compiles to:

var Person;
Person = function() {
  var privateFunc;
  function Person() {}
  privateFunc = function() {};
  Person.prototype.publicFunc = function() {};
  return Person;
}();

2) I'd love to hear what your problems are with the output JS -- it's more or less the same as the current output for classes.

3) Yes, you can define the constructor function.

class Animal
  (name) ->
    @name = "Animal " + name

Compiles into:

var Animal;
Animal = function() {
  function Animal(name) {
    this.name = "Animal " + name;
  }
  return Animal;
}();
michaelficarra commented 14 years ago
  1. Ah, so prototype methods are defined with the : operator? Is it inconsistent then to use @static = -> rather than @static: ->? Also, this strays from how all other variables / functions are defined elsewhere. My proposal (I hate to keep promoting my own work like this, I sound like some of my old professors) did not have that problem.
  2. I was just fond of the method StanAngeloff proposed in the last thread of wrapping the executable body in a function whose context was ClassName.prototype. But doing it that way may not be best. Either way, we should not worry about it until after we agree on syntax / semantics (which I now see are more fully defined already in the current proposal than I thought).
  3. Doh! I can't believe I didn't see that. Perfectly reasonable way to define the constructor.

A note I would like to bring to this thread from one of StanAngeloff's posts in the last thread is that @ symbolizes an instance everywhere else. That may be a small point of confusion for newcomers / unfamiliars. A counterexample to this, though, is ruby's usage of self inside instance methods (referring to the instance) and inside its executable class bodies (referring to the class).

StanAngeloff commented 14 years ago

I can't wrap my brain around the syntax, it doesn't make any sense. Why would an implicit object in a block be turned into a prototype function?

class Klass
  if env is 'development'
    randomKey: -> 'I am not an object, I am a class member.'

I like the idea, but the execution is poor. For one, accessing this is inconsistent:

class Klass extends Base
  @methodOnThis()
  anotherMethodOnThis: ->

When you are using the @ you are referencing a method on this, but to define new methods, you simply plug the name in an object bag.

Static and instance properties are also inconsistent:

class Klass extends Base
  @methodOnParentFromInstance()
  @staticPropertyOnKlassNotThis = 'static'
  memberPropertyOnThis: -> 'instance'

Here @ represents two things, either a method invocation on the instance or a static property on the class. The assignment syntax also differs on static vs. instance members.

Having the constructor hanging around as an anonymous function at the top level implies it can't be part of a conditional statement, such as if env is 'development'? I'd much rather see the old constructor back and yes, we have means to override the constructor already (a named function is generated).

640 has seen much better proposals for syntax. All hands and legs up (#twss) for this proposal, however the syntax clearly needs refining... a lot.

EDIT: mid-air collision with michaelficarra, same points there.

Ezku commented 14 years ago

I'm glad you decided to give executable class bodies another go. I'm with Michael, though - this needs to be thought through carefully before merging with master.

So what you're doing here is taking Stan's proposal of manipulating the class definition context and creating a syntactical metaphor around that, but going one step further and having the context be the static class instead of the class prototype. I assume your goal was at least partly in reducing the amount of operators required, eg. @@ for self (static) vs. @ for this (prototype).

  1. The concept makes sense if you think you're imperatively manipulating a prototype in a static context. This means thinking about foo: bar as an alias for @::foo = bar. Might not be bad, because you're bringing the prototypal aspect of class creation a bit closer to the user. You need to note, however, that this is only dressing up the operator problem a bit differently. I applaud your efforts in minimizing the amount of keywords and syntax to be learned, but having @ mean two different things in close proximity is dangerous unless you come up with a good enough metaphor for describing the feature. Are @ and : while using @ for two things, as opposed to @@ and @, really such a good solution?
  2. I'm not sure I like the implicit constructor part. This is mainly because it doesn't really reflect the generated Javascript's structure and does not feel like it's necessary. Is there something wrong with constructor?
  3. As for metaprogramming, my core concern is about needing to extend a class to get to use its metaprogramming capabilities. Requiring the metaprogramming helper functions to be part of the same class hierarchy, I find, would significantly reduce the applicability of the feature. Is there a way I can include a set of static methods in the scope without extension? In Ruby, I understand you'd extend a metaclass to provide helpers such as attr to all classes. Might metaclasses be possibly applicable in the context of Coffeescript, or can we learn something from their application in other languages? On a conceptual level, I think they'd be about declaratively affecting the scope of class body execution and therefore the available static methods.

Mixins, as their implementation currently stands, do not provide an adequate solution for integrating metapgrogramming capabilities, because their contents are only applied after class declaration. For this feature to be complete and stand on its own, I think something additional is required.

devongovett commented 14 years ago

I don't like the syntax either. I don't like the idea of dropping constructor - it looks inconsistent from the definitions of every other method on the class.

Why are executable bodies even necessary? You can accomplish all of the examples here with the current class syntax.

Why write:

class Logger
    if env is 'development'
        log: (err) -> console.log err
    else if env is 'production'
        log: (err) -> console.error err

when you can just write:

class Logger
    log: (err) ->
        if env is 'development'
            console.log err
        else if env is 'production'
            console.error err

it is simpler, and makes more sense.

The metaprogramming bit is nice, but isn't something that can't be accomplished using ordinary CoffeeScript. Just do the same thing in the constructor function and you are fine.

class Model
    attr: (name) ->
        this[name] = (val) ->
          if val?
            @["_" + name] = val
          else
            @["_" + name]

class Robot extends Model
    constructor: ->
        @attr 'power'
        @attr 'speed'

#...

Maybe I am missing something here, but it doesn't seem to me to be that much simpler, or better in any way to what we already have.

satyr commented 14 years ago
$ bin/coffee -bsp
class A
  privDict = if inv then (v): k else (k): v

var A;
A = function() {
  var privDict;
  function A() {}
  privDict = inv ? A.prototype.v = k : A.prototype.k = v;
  return A;
}();

Intended?

jashkenas commented 14 years ago

I adopted satyr's naked constructors because they get rid of yet another special keyword, while providing a syntax closer to what the constructor function really is -- i.e. the class object. For example:

# constructor function:
Person = (name) -> 
  @name = name

# class form:
class Person
  (name) ->
    @name = name

... but if the consensus is that it's better to keep the constructor label, that would certainly be an easy change to make.

Another change we could make is the switch of static member assignment from = to :. If we made it work with both, the syntax for these executable classes would be identical to what we currently have on master and 0.9.4.

Finally -- satyr's point about literal objects is well taken, we need a rule for distinguishing the uses. On his original branch, only top-level object-literals were treated as prototype properties, but that doesn't make executable classes very useful. Perhaps we can say that an object literal to the right-hand-side of an assignment is just an object, and is a prototype property otherwise...

ghost commented 14 years ago

Wow! I hadn't been blown away with a new proposal since that "implicit object properties" one.

Conditionally define methods

Great! Especially useful when you don't want to define some functions in specific contexts -- like when using the same module in both client and server.

\ Naked constructors -- no constructor keyword needed **

class Animal
  (name) -> 
    @name = "Mr. " + name

I like it. Why make things more verbose than they need to be?! Simple, visually clear. What CoffeeScript aspires to be.

Metaprogramming

class Model
  @attr = (name) ->

Very useful example. This is perfect for defining models.

My Conclusion

I'm very excited by this proposal! The metaprogramming feature especially solves some big problems I've been having when defining data models.

There are some things to iron out, I know, but I love what just became possible!

kainosnoema commented 14 years ago

+1 on most of this proposal.

The biggest benefit here in my mind is the static inheritance. The executable body and metaprogramming possibilities are great, but static inheritance is a very basic feature that I've been waiting for.

Great news.

hen-x commented 13 years ago

Instead of eliding the constructor: label altogether, why not change it to new:? Short, logical, mirrors use, and already a keyword.

Ezku commented 13 years ago

That's an interesting proposition, sethaurus. Possibly confusing, because new would not actually handle instantiation but merely initialization - new Foo would not mean Foo.new(). Refer to the way new works in Ruby.

hen-x commented 13 years ago

But in JS and CS— and unlike ruby — instantiation and initialization are already a single, indivisible step. The syntax for constructing an instance, new Thing(), is doumented. Labelling the initializer with constructor: doesn't imply that you create a new instance by calling Thing.constructor(), so nor should new: imply Thing.new(). Since we need a pseudo-method to be invoked by the new operator, calling it new: reduces the cognitive overhead, at least in my mind.

jashkenas commented 13 years ago

Alright ... pushed some tweaks to executable. The naked functions are gone, and constructors are now defined with constructor: as before. The only syntax difference from master now for simple classes is @static = val...

I've also made it so that although defining prototypal properties is the default, you can also force the use of private object literals, simply by using explicit braces. Hopefully things will compile more or less as expected:

class A
  privateUrls = 
    home: '/home.html'
  go: ->
    load privateUrls.home

Into:

var A;
A = function() {
  var privateUrls;
  function A() {}
  privateUrls = {
    home: '/home.html'
  };
  A.prototype.go = function() {
    return load(privateUrls.home);
  };
  return A;
}();
TrevorBurnham commented 13 years ago

Altogether, the proposed changes look great to me. Improvements all around.

I'm chiming in a bit late, but I really liked the naked constructors. The approach reduces verbosity, frees up a keyword, and makes constructors look (aptly) more distinct from other functions.

Perhaps most importantly of all, it reduces cognitive effort—every time I type constructor, I think to myself, "Do I have that right?" It would be more sensible to either adopt the C/Java convention of reusing the class name, or perhaps the Python __init__, rather than using a long word that appears to define an ordinary function.

The constructor keyword approach has always felt awkward to me, and I think satyr's solution is quite elegant.

ghost commented 13 years ago

What TrevorBurnham said. :)

jashkenas commented 13 years ago

Ok -- after messing around with a bunch of different test cases, I'll put the naked constructors back in. If you want to discuss the alternatives, this afternoon is a good time to speak up in #coffeescript...

jashkenas commented 13 years ago

Since overall reception to this branch has been overwhelmingly favorable, and I think it's worth nailing down, I've merged executable back into master, and we can continue to refine it there. Leaving this ticket open until we have the final form of this syntax nailed down.

michaelficarra commented 13 years ago

I, like StanAngeloff, am still not happy with the current syntax of just putting object literals in the class definition to define methods. Why can't we just use equality and the @, which is used everywhere else to mean instance method?

I've also made it so that although defining prototypal properties is the default, you can also force the use of private object literals, simply by using explicit braces.

I'm ESPECIALLY unhappy that there's a semantic difference between implicit and explicit objects. That one, I cannot stand for.

And although everyone, myself included, does feel very positive about this new feature, I really don't think it should be merged to master just yet. It sets a precedent for merging in huge changes like this less than 48 hours after they were proposed. What's so bad about keeping it on a separate branch?

Finally, I liked that we were using the constructor name to define constructors. Naked constructors are okay, but I usually like being a little more explicit, especially if we would be using the @ syntax for instance methods. I think an even better name for constructor would be new, that way we can define a ClassName.new method as well and have an awesome new ruby-esque syntax for instantiation.

satyr commented 13 years ago

I'm ESPECIALLY unhappy that there's a semantic difference between implicit and explicit objects. That one, I cannot stand for.

Agreed.

Things are much simpler for Coco, where the magic occurs only on the top level naked function/object. So this Coco code

class C
  ->
  {}

desugars to

function C ->
C:: import {}

mirroring the primitive JS idiom

function C(){}
C.prototype = {};
devongovett commented 13 years ago

Problems I see with this syntax:

  1. Naked constructor functions look inconsistent with way other methods are defined, and the change would not be backwards compatible with current CoffeeScript code. This means that users would have to go through their code and manually switch to using this syntax. I think we ought to consider that, because I know I don't want to go through all that trouble, when the truth is that using the constructor property was really just fine!
  2. Why create bloated JS code when it isn't necessary? Most of the time, I will not be making use of executable class bodies. Why create the extra bloat (closure wrapper) when the executable bodies aren't being used?
  3. The same thing about backwards incompatibility goes for the change in static method syntax from @prop: value to @prop = value.

I am happy with this feature being added if it doesn't change the behavior of my already written and working code.

satyr commented 13 years ago

Why create the extra bloat (closure wrapper) when the executable bodies aren't being used

Constructors will be wrapped regardless of this change due to JScript bugs. See #729.

devongovett commented 13 years ago

@satyr: say what? We weren't wrapping before and everything worked just fine...

TrevorBurnham commented 13 years ago

@devongovett On your third point: While backward compatibility is nice, @prop: value was always weird—the one place in CoffeeScript where @ didn't mean this. So, I'm glad to be rid of that syntax.

@michaelficarra Could you elaborate on your objections with specific examples?

devongovett commented 13 years ago

@TrevorBurnham maybe I'm misunderstanding you, but switching from @prop: value to @prop = value doesn't really change anything about what @ refers to...

TrevorBurnham commented 13 years ago

[Update: Reconsidered, see below.]

michaelficarra commented 13 years ago

@michaelficarra Could you elaborate on your objections with specific examples?

@TrevorBurnham: I'm not quite sure on what you want me to elaborate. Can you quote specific statements I made?

Also, @devongovett: Coffeescript is still in alpha, meaning its syntax and semantics WILL change and cannot be relied upon. From the official documentation:

Disclaimer: CoffeeScript is just for fun. Until it reaches 1.0, there are no guarantees that the syntax won't change between versions.

It's unfortunate if you have to change code you already wrote (I'm in the same boat), but we are not looking to maintain backwards compatibility with any other alpha versions of CS. We should not take that point into account. To continue compiling your code the way it is, you can always make it rely on a specific (alpha) version of Coffeescript, but for right now, it's probably best to flow with the changes.

TrevorBurnham commented 13 years ago

Uhhh, did several comments get deleted from this thread somehow...? The latest I'm seeing is michaelficarra's that concludes "it's probably best to flow with the changes."

StanAngeloff commented 13 years ago

Uhhh, did several comments get deleted

Yup. It is actually much worse than it sounds in that blog post as you can tell.

TrevorBurnham commented 13 years ago

[As it happens, I did save the proposal I posted before the outage. Here it is again...]

OK, I've taken a more serious look at the new syntax, so let me take a step back. On the current master, a simple class can look like

class Model
  doSomething()
  count = 0
  @staticFunc = -> 'foo'
  instanceFunc: -> 'bar'
  () -> console.log @instanceFunc() + ++count

There are several unintuitive things here, notably:

  1. Why isn't that call to doSomething() in the constructor? Weird. You essentially have two subtly different ways of doing constructor-y things, and you can mix the two freely.
  2. It's hard to explain why @staticFunc is static, or why a reference from the constructor to @staticFunc would fail (you would have to write Model.staticFunc instead). Also, note that @staticFunc = and @staticFunc: are equivalent, setting the stage for annoying debates about which style is better.

But I come to praise the new class syntax, not to bury it! Several interesting things are being done here; for instance, note that @ and this compile to Model within the class body. I think we can build on those things and come up with a clearer, yet equally powerful syntax:

  1. Allow only assignment expressions in the class body, and require them to come before the constructor to clarify the execution order.
  2. Require static assignments (equivalent to Model.property = ...) in the class body to use : rather than = (paralleling the public instance method syntax).
  3. Compile @@ to the class name, and allow its use within class methods as well as the class body. Disallow use of @/this in the class body, as they'd just mean the same thing.

With these changes in place, the class declaration from above would look like

class Model
  count = 0
  @@staticFunc: -> 'foo'
  () ->
    doSomething()
    console.log @instanceFunc() + ++count
  instanceFunc: -> 'bar'  

And you'd be able to reference @@staticFunc from the constructor as well as other functions.

These changes would preserve all of the power of the new syntax, while making CoffeeScript classes look and feel a lot more intuitive. To someone who understands JavaScript functions and has used objects in any other language, you would be able to explain CoffeeScript classes thusly:

  1. class is a special function declaration. Because it's a function, anything defined in the class body with = is visible only within the class.
  2. To define the constructor, write a nameless function: (arguments...) -> ...
  3. To define a public instance-level method or property, use the hash syntax: property: ... Refer to these as @property from within instance methods.
  4. Static methods and properties are defined using the @@ prefix, as in Ruby, and the hash syntax: @@property: ... They can be referenced anywhere within the class via either @@property or ClassName.property.

Thoughts?

danielribeiro commented 13 years ago

Great proposal. Don't really care about not having to type constructor for a class' constructor. It doesn't bother me in Ruby/Python either.

jashkenas commented 13 years ago

Just to pipe back in with a ticket-that-was-erased-by-the-github-crash, here:

The new executable classes are backwards-compatible, syntactically, with existing classes. This means that @static: val continues to work, and constructors are labeled with constructor: ...

michaelficarra commented 13 years ago

I'm not sure if this ticket should have been closed just yet. There are still a lot of unanswered issues that many people have brought up. @jashkenas: can you take another read-through of this thread and make sure you're still comfortable closing it with things in their current state? There were a lot of really good points that I don't want ignored.

jashkenas commented 13 years ago

Yes -- gave the ticket another read through, and I am comfortable closing it in it's current state. Feel free to drop by #coffeescript if you'd like to chat about particular bits. The main opposing proposition here is something similar to Stan's #640, which we're not going to do: it's a poor syntax relative to this one, and privileges "private" (local) properties over prototypal properties, which defeats the purpose of a class definition: to define a prototype. If you just want a list of local functions, use a closure.

The bit that I'm least comfortable with is the rules for converting key: val assignments into prototypal properties, but at the moment, it's backwards-compatible with 0.9.4, and we can continue to refine it from there.

michaelficarra commented 13 years ago

How about the difference I pointed out between implicit and explicit object syntax? There should never be a difference between those two. It's an extremely slippery slope, conveying to people that they are actually two different things, when in any other context they are not.

Also, there seemed to be no real consensus on how we should define the constructor, syntactically speaking. I'm fine with pretty much anything suggested (implicit constructor, constructor special case, new special case, etc.), but we should hear some arguments for and against these.

And lastly and probably most importantly, the method assignment notation: StanAngeloff and I especially were pushing for uses of @, @@, and = so that class definitions were not so different from other coffeescript constructs.

Maybe these (and unlisted others) should all be made into separate issues, and discussion should continue there? I'm fine with pushing out another point release with the way things are now, but these should be discussed before 1.0. I'd be willing to start these issues tonight if nobody else takes it up before then.

jashkenas commented 13 years ago

The difference between implicit and explicit object literals is the piece of it I'm least comfortable with ... but I think it's the correct syntax here. Think of key: value as assigning a property, and var = value as assigning a variable. Here we're assigning properties of the class. Think of it like this, in terms of tokens:

{ key: value }

class key: value outdent

Constructors continue to be defined with constructor: because none of the alternatives are demonstrably better, and this is backwards-compatible.

Prototype property assignment notation cannot use an @ symbol. The entire point of having a class definition is to facilitate the assignment of prototype properties -- we can't require them to be prefixed with this -- especially when this is not a reference to the prototype. It doesn't make sense semantically, and optimizes the syntax for the wrong thing.

Ezku commented 13 years ago

jashkenas: I find your arguments entirely agreeable and, although I was worried about being too hasty with this issue, support your decision in closing it.

michaelficarra commented 13 years ago

@jashkenas: care to give a reason for this re-opening?

jashkenas commented 13 years ago

Yep. @wycats wants to make the case for bringing back the extended hook, so I re-opened this ticket for him.

devongovett commented 13 years ago

I have a case for the extended hook to return as well... So, here goes.

Basically, since properties on the constructor are copied over when extending but not deep copied, if you had an object or array property on the parent class, you get a reference to the same object on the extended class, which may not be the desired behavior. Here is an example, from a piece of my own code, as well as how I got around it:

I'm building an ORM in CoffeeScript, and on the constructor of each data model I have a fields object that stores information about each defined property for records of that type. Because all models extend from a base model class or from other models, when I extend, the fields object gets copied over as desired, but because it is a reference to the property on the parent class, any fields I add to the extended model get added to the parent model as well - definitely not desired. I fixed this by dynamically checking whether the fields object was equal to the one on the super class (using CoffeeScipt's __super__ property, and deep copy it if so. This was only possible because I have a method that gets called for every added field, but you can imagine a situation where that isn't the case.

There are a few possible fixes for this... If there was an extended hook, I could run my deep copy ahead of time on those properties. The other option would be for CoffeeScript to do deep copies when extending classes, but this would be a larger change for the language...

So that's my case for the return of the extended hook. I'm sure @wycats has a good one as well.

michaelficarra commented 13 years ago

Ah, yes, that one. You could probably already tell, but I'm in favor of an extended call as well.

keithnorm commented 13 years ago

I forked coffeescript to add an extended hook so I could write jQuery plugins as classes that extend a base class. It looks something like this (the ugly part is parsing the function name out of the constructor, but besides that I like it):

class NodeList
  @extended: (base) ->
    name = base.toString().match(/^\s*function\s+([^\s\(]+)/)[1]
    if name
      $.fn[name] = (options)->
        @each (i, el) ->
          $el = $(el)
          return  if $el.data(name)
          instance = new base($el, options)
          $el.data name, instance

class MyPlugin extends NodeList
  constructor: (element, options) ->
    console.log element, options

//now you can do $('.foo').MyPlugin({foo: 'bar'});
//and you get the added benefit of abstracting logic away from a jQuery specific implementation
michaelficarra commented 13 years ago

@keithnorm: Instead of parsing the function name out, why don't you just pass it to the extended hook? It's not like it's not available at compile time...

keithnorm commented 13 years ago

@michaelficarra: Since the extended hook is called from the __extends method, so that method should only know about a generic parent and child, it seems like the only way to do this would be to store the name as a property on each class. That sound right?

MyPlugin = (function() {
  MyPlugin.name = 'MyPlugin';
  __extends(MyPlugin, NodeList);
  function MyPlugin(element, options) {
  }
  return MyPlugin;
})();
michaelficarra commented 13 years ago

Some alternative solutions:

  1. pass the name through to the __extends call (a little ugly)
  2. move extended call from __extends to the class-defining IIFE (not that great)

On every major engine but Trident, that name property you define is already defined and not writable. So your solution would be best. Unfortunately, we already tried that approach in #1272, but @jashkenas shot it down.

keithnorm commented 13 years ago

Ok cool I can work around the name issue for now, but as far as getting the extended hook merged in, what are the chances? I looked at your gist @michaelficarra and we have arrived at the same conclusion. What is the push back?

grayrest commented 13 years ago

I'm going to me too a request for an extends hook. I'm currently patching my install of coffeescript to change __super to superclass so I can use the class...extends syntax with yui3.

jashkenas commented 13 years ago

I know it's been a while, but is anyone in here still hankering after the extended hook ... or have y'all found manual registration to work just as well?

danielribeiro commented 13 years ago

I've been sticking with 0.9.4

But there are so many nice things on the newer versions, that I'm thinking about forking it and adding extended hook back. And metaprogramming through plugin support back as well.

michaelficarra commented 13 years ago

@danielribeiro: wow. I would have forked it long ago. It's not like it'd be hard to maintain. How often does that single line of code change? Almost never.