Subclassing ES6 objects with ES5 syntax.

C. Scott Ananian ecmascript at cscott.net
Wed Apr 29 15:44:20 UTC 2015


On Wed, Apr 29, 2015 at 1:06 AM, Brendan Eich <brendan at mozilla.org> wrote:

> Kevin Smith wrote:
>
>> So what would the ideal Promise.resolve semantics do?  I'm not sure,
>> maybe use SpeciesConstructor instead of [[PromiseConstructor]]?
>>
>
> This removes the wart in my view, has no less integrity. C. Scott?


Making this concrete, here would be the new text for 25.4.4.5
Promise.resolve(x):

> The resolve function returns either a new promise resolved with the passed
> argument, or the argument itself if the argument is a promise produced by
> this constructor.
> 1. Let C be the this value.
> 2. If IsPromise(x) is true,
>     a. Let constructor be the value of SpeciesConstructor(x, %Promise%)

    b. If SameValue(constructor, C) is true, return x.
> 3. If Type(C) is not Object, throw a TypeError exception.
> 4. Let S be Get(C, @@species).
> 5. ReturnIfAbrupt(S).
> 6. If S is neither undefined nor null, let C be S.
> 7. Let promiseCapability be NewPromiseCapability(C)

[...remainer elided...]


Step 2a is the only change.  (It was previously "Let constructor be the
value of x's [[PromiseConstructor]] internal slot.")

Thinking this through, the purpose of the `@@species` property, from the
spec: "Promise prototype methods normally use their this object’s
constructor to create a derived object. However, a subclass constructor may
over-ride that default behaviour by redefining its @@species property."

So with this change, `P.resolve()` is guaranteed to return an object whose
constructor property is `P.@@species`, whether it takes the shortcut in
step 2 or not.  That seems pleasantly less warty.

The alternative (implemented in core-js) is:

> 2. If IsPromise(x) is true,
>     a. Let proto be the value of x.[[Prototype]]

    b. If SameValue(proto, GetPrototypeFromConstructor(C,
> "%PromisePrototype%")) is true, return x.
>

But that seems to break the expected behavior of @@species.  That is, a
promise subclass `P1` with `P1.@@species == P2` would shortcut objects of
type `P1` through `P1.resolve()` but return objects of type `P2` if the
shortcut wasn't taken.  (Forgive the looseness of the word "type" here.)

That seems somewhat surprising.  But I don't have a concrete use case in
mind for setting `Promise[@@species]`.  Perhaps someone else has one, and
can say what behavior they'd prefer to see?

Lacking such a justification, the first alternative (using
[[SpeciesConstructor]]) seems to be more consistent with the rest of the
spec and less surprising.  So that has my vote.
  --scott
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150429/2db9e19f/attachment.html>


More information about the es-discuss mailing list