On Feb 17, 2010, at 4:30 PM, Mark S. Miller wrote:

Tom & I started with the question "If we could have any syntactic sugar we wanted, how would we express traits?". Once we had a plausible answer, we asked "How close could we come with a pure library, with no new syntactic sugar?". The answer was, so close that the remaining benefit of additional syntax was tiny, so we dropped it.

First, kudos for traits.js, it has the long-sought-after (even back in ES4 days, with "fixtures") ability to specify fixed sets of methods and properties that can be composed freely, but which cannot be overridden without extra effort (if one allows that calling override is somehow "extra" compared to calling compose). Great work.

Second, demurral from the claim that the benefits of syntax are tiny, for either users and implementors.

Users have to put up with Trait.object({}) instead of something like trait {} (without an "extends" clause), in the following example from your mail (revised to use const to create a frozen function with frozen prototype bound to a block-scoped const binding):

    const Point(privX, privY) {
      let privInstVar = 2;
      const privInstConst = -2;
      let pubInstVar = 4;
      const pubInstConst = -4;
      return Trait.object({
        toString: function() {
          return ('<' + this.getX() + ',' + this.getY() + '>');
        },
        getX: function() { return privX; },
        getY: function() { return privY; },
        get pubInstVar() { return pubInstVar; },
        pubInstConst: pubInstConst
      });
    }

This is non-trivially noisy, but admittedly less of an issue (in this example, at any rate) for users than it is for implementors, considering that graphics-intensive code might make 1e6 Points, with 3e6 bound methods (if I'm counting correctly).

Yet the syntactic noise and unchecked-till-runtime boilerplate tax remain an issue for users, and the Object.freeze calls add to this user-facing complexity if you revert the const Point(...) {...} change to use a function definition.

Syntax errors instead of runtime typo complaints are always a win for users.

If you keep that new const syntax, then there's no backward- compatibility argument against better trait syntax, by which users could say what they mean more simply and correctly, and implementations could optimize much more easily.

For implementors as well as bean-counting users, optimizing bound methods can be important. JS is being used to push pixels, and not just pixels: the scene graph, physics, and game logic all want speed at scale. It's a safe bet that programmers won't use traits only "in the small".

Your posts seem to ask or suggest about implementations pattern- matching for layered applications of Object.freeze and Function.prototype.bind, which is a tall order in itself.

But even doing such matching is pessimistic if it results in a "bound method pair" (meth, self) for a given method value (meth) and receiver object (self), created and frozen at the point where traits.js calls freeze(bindThis(meth, self)).

Bound methods need not be reified unless extracted as funargs (even if only as operands of ===, e.g.), or frozen unless tampered with. If they're (typically, or only ever) called on the right receiver, then the cost of creating a bind result can be avoided.

Optimizing to defer layered freeze/bind combinations until method value extraction or mutation attempt requires more than fancy pattern- matching on the part of an implementation. It requires a read barrier. Getters already require such a barrier, but it is on the slow path. The overhead of a method binding/freezing barrier could be hidden in that slow path, but it is no picnic for implementors even if they have explicit, unambiguous syntax.

You could say "that's why implementors make the big bucks" (I've written this in the past, half in jest).

But I'm not concerned only about a once-per-implementation-effort tax on implementors who wish to avoid 3e6 methods per point, or other such poor performance scaling. I'm more concerned about complexity, which breeds bugs (including exploitable ones if the implementor is working in an unsafe language).

Put together the user and implementor taxes, and you have sufficient cause for new syntax.

Add to this tax revolt the plain desire for better syntax-as-user- interface. If you want const f(){}, why //wouldn't// you want declarative trait syntax?

/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to