Minimalist Classes

Jeremy Ashkenas jashkenas at gmail.com
Tue Nov 1 06:53:56 PDT 2011


>
> This doesn't sound right to me. What happens if you call the same method
> on another object while the super-resolution is still active for the first
> call? IOW, this sounds like it has similar problems to dynamic scope; the
> behavior of a function becomes sensitive to the context in which it's
> called, which is unmodular.
>
>
> The problem isn't so much whether it's possible to come up with a
> semantics by changing the runtime; I'm sure we could do that. The problem
> is finding a way to get the semantics you want without taxing the
> performance all other function calls in the language. (Also known as a
> "pay-as-you-go" feature: if you don't use the feature, it shouldn't cost
> you anything.) We don't know how to do that for super().
>

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.

If you agree, then a super() that resolves dynamically is the way forward,
and things get easier: super() can be added without classes, classes can be
added without super(), and if both make it in, both can work seamlessly
together.

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.


> 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. 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

... particularly the bit about adding all of the functional helpers to the
"wrapper" object's prototype, to make chaining style possible.

On the other hand, 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;
  }
}, _)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111101/711ac03f/attachment-0001.html>


More information about the es-discuss mailing list