traits are now impossible in ES6 until ES7 since rev32?

Claude Pache claude.pache at gmail.com
Fri Feb 6 10:35:11 PST 2015


> Le 6 févr. 2015 à 18:04, Ben Newman <benjamin at cs.stanford.edu> a écrit :
> 
> The specific line in rev32 of the spec that prevents [[Call]]ing "classConstructor" functions is 9.2.2.2 <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-function-objects-call-thisargument-argumentslist>:
> 
> 2. If F’s [[FunctionKind]] internal slot <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object-internal-methods-and-internal-slots> is "classConstructor", throw a TypeError exception.
> 
> From my reading of the spec, I think the idiomatic Foo.call(this) pattern that Luke Scott described would work if we simply changed that line to something slightly weaker:
> 
> 2. If F’s [[FunctionKind]] internal slot <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object-internal-methods-and-internal-slots> is "classConstructor" and InstanceofOperator <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator>(thisArgument, F) is false, throw a TypeError exception.
> 
> This mirrors an assertion discipline that has saved me from many bugs due to forgetting the new operator:
> 
> function Base() {
>   assert.ok(this instanceof Base);
>   ...
> }
> 
> function Derived() {
>   assert.ok(this instanceof Derived);
>   Base.call(this);
>   ...
> }
> 
> Derived.prototype = Object.create(Base.prototype, {
>   constructor: { value: Derived, ... }
> });
> 
> Is the addition of the instanceof check naive? Would it invalidate any of the assumptions involved in the invocation of F?
> 
> I'm happy to file a bug if this change merits further consideration.
> 
> It may be worth noting that only constructors created by class syntax will have their [[FunctionKind]] internal slot set to "classConstructor", so (even with the current spec) you can still invoke ordinary constructor functions using [[Call]]. However, it seems regrettable that you have to know whether a constructor was created by class syntax in order to know whether the Foo.call(this) pattern is safe.

The issue is deeper. In short, you cannot feed an ES6-class constructor with an already allocated object, whatever that object is.

With a user-defined good ol' pre-ES6 constructor:

    foo = new Foo // allocate a Foo object and initialise it
    
is usually equivalent to:

    foo = Object.create(Foo.prototype) // allocate a Foo object ...
    Foo.call(foo) // ... and initilise it

With the new ES6-class semantics, for the sake of subclassability of builtins, it is, on purpose, not possible to separate allocation from initialisation that way. Even before ES6, builtin classes, did not support such a pattern, e.g.,

    arr = new Array(2, 3) // allocate a new array and initialise it

is in no way equivalent to:

    arr = Object.create(Array.prototype) // allocate an new object, but it won't be an array...
    Array.call(arr, 2, 3) // ... and don't initialise it, but create uselessly a new Array
    
And it appeared that introducing the possibility for builtins to have separate allocation and initialisation phases was problematic.

—Claude


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150206/c8a390ab/attachment.html>


More information about the es-discuss mailing list