Minimalist Classes

David Herman dherman at mozilla.com
Tue Nov 1 07:22:30 PDT 2011


> I think one piece of this is worth reiterating: As long as JS.next classes are mostly sugar for prototypes, and prototypes aren't going to be deprecated or removed in the next version of JavaScript (two propositions that I think most of us can get behind) ... then it's very important that super() and new class syntax *aren't* coupled. An ES6 super() that fails to work at all with regular prototypes would be a serious problem. It would make interoperating between vanilla prototypes and prototypes-built-by-classes much more difficult than necessary, and the feel of the language as a whole much more fragmented.

I agree that we should avoid introducing things you can do with classes that you can't do with prototypes.

> If you agree, then a super() that resolves dynamically is the way forward.

But I disagree with this claim. Allen's triangle operator (which is semantically well-designed but I believe needs a better syntax) gives you just this ability to do super() with prototypes and without classes. And classes are still sugar.

> I don't think that an efficient, pay-as-you-go dynamic super() will be easy, but with the technical chops of TC39 at your disposal, it should be possible. Expanding the rough sketch from earlier messages:
> 
>   * If a function doesn't use super(), there is no cost, and no change in semantics.
>   * The first-level super() call is easy, just use the method of the same name on the __proto__.
>   * When passing into a super(), add a record to the call stack that contains [the current object, the name of the method, and the next level __proto__].
>   * When returning from a super(), pop the record from the call stack.
>   * When making a super() call, check the call stack for a record about the current object and method name, and use the provided __proto__ instead of this.__proto__ if one exists.

This approach still gets confused if you recursively call the same method on the same object in the middle of a super-dispatch. Bottom line: it's not equivalent to the behavior where every function call receives an extra argument (and which no one in TC39 knows how to implement in a pay-as-you-go manner).

> So I guess in theory I agree it'd be nice if super() and class could be designed completely orthogonally, but in practice they affect each other. But at the same time, I think a class syntax where the body is restricted to be declarative is actually a nice sweet spot anyway. You can still dynamically create classes just like always, but the declarative form gives you a sweet and simple syntax for the most common case.
> 
> It's definitely the most common case, but a JavaScript class syntax that is only able to create instances with a static shape would be severely limited compared to current prototypes.

Not at all! Current prototypes have to be created as objects. How do you create an object? Either with an object literal, which has a static shape, or via a constructor call; anything else you do with assignments. With literal classes you have exactly the same options at your disposal.

> Many existing libraries and applications would be unable to switch to such a syntax. One familiar example off the top of my head is Underscore.js:
> 
> http://documentcloud.github.com/underscore/docs/underscore.html#section-127

Concrete examples are *super duper awesome* -- thank you so much for bringing this into the discussion.

> ...with the minimalist class proposal in this thread, switching this library over to use them would be simple (if not terribly pretty):
> 
> class wrapper _.extend({
>   constructor: function(obj) {
>     this._wrapped = obj;
>   }
> }, _)

It's true that with literal classes you wouldn't be able to put all the initialization inside the class body, but you could still declare it with a class.

    class wrapper {
        constructor: function(obj) {
            this._wrapped = obj;
        }
    }

    _.extend(wrapper.prototype, /* whatever you like */);

The rest you could do as-is; the difference here is minimal, and IMO it's a good thing to distinguish the fixed structure from the dynamically computed structure. Anyway, JS has plenty of precedent for that.

Dave

PS I also think the "extend" pattern could be done with a cleaner generalization of monocle-mustache:

    wrapper.prototype .= _;

But that's fodder for another thread...

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111101/8e0f71a4/attachment-0001.html>


More information about the es-discuss mailing list