That makes sense for sure, but I don’t think subclassing is impacted by
receiver constraints in this regard either way, since subclasses will still
be “IsPromise” promises. What is affected is portability of the methods to
“non-IsPromise” thenables. Catch not requiring an IsPromise receiver makes
sense from that angle:

```js
OffbrandPromise.prototype.catch = Promise.prototype.catch;
```

But if portability to non-native, non-Promise-subclass thenables is the
goal, I’d still have expected finally to be the same “level” of generic as
catch. Neither require their receiver to be an IsPromise-promise, but catch
doesn’t even require its receiver to be an object, while finally does. This
is a very minor thing obviously, but I wondered if it might still be web
safe at this point to make catch require its receiver to be an object like
finally does. It would be more consistent, and it’s pretty hard to imagine
the current ability to call catch on a primitive, as in the second example
above, being a useful behavior.

On Fri, Jul 20, 2018 at 7:10 PM Jordan Harband <ljh...@gmail.com> wrote:

> This is intentional - `catch` delegates to `then`, so that a subclass that
> overwrites `then` doesn't have to also override `catch` (and the same for
> `finally`, which also calls into `then`).
>
> On Fri, Jul 20, 2018 at 4:29 AM, Darien Valentine <valentin...@gmail.com>
> wrote:
>
>> In `Promise.prototype.then`:
>>
>> > 1. Let promise be the this value.
>> > 2. If IsPromise(promise) is false, throw a TypeError exception.
>> > [ ... ]
>>
>> In `Promise.prototype.finally`:
>>
>> > 1. Let promise be the this value.
>> > 2. If Type(promise) is not Object, throw a TypeError exception.
>> > [...]
>>
>> In `Promise.prototype.catch`:
>>
>> > 1. Let promise be the this value.
>> > 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
>>
>> First, this means that only `then` requires the this value to be a
>> Promise:
>>
>> ```js
>> for (const key of [ 'then', 'finally', 'catch' ]) {
>>   try {
>>     Promise.prototype[key].call({
>>       then: () => console.log(`${ key } doesn’t brand check its this
>> value`)
>>     });
>>   } catch (err) {
>>     console.log(`${ key } does brand check its this value`);
>>   }
>> }
>>
>> // > then does brand check its this value
>> // > finally doesn’t brand check its this value
>> // > catch doesn’t brand check its this value
>> ```
>>
>> Second, note that `Invoke` uses `GetV`, not `Get`. Thus:
>>
>> ```js
>> for (const key of [ 'then', 'finally', 'catch' ]) {
>>   try {
>>     String.prototype.then = () =>
>>       console.log(`${ key } casts this value to object`);
>>
>>     Promise.prototype[key].call('foo');
>>   } catch (err) {
>>     console.log(`${ key } doesn’t cast this value to object`);
>>   }
>> }
>>
>> // > then doesn’t cast this value to object
>> // > finally doesn’t cast this value to object
>> // > catch casts this value to object
>> ```
>>
>> On reflection, I think I see the logic to this:
>>
>> - `Promise.prototype.then` ends up executing `PerformPromiseThen`, which
>> requires its first argument to be a native promise object.
>> - `Promise.prototype.finally` ends up executing `SpeciesConstructor`,
>> which requires its first argument to be an object.
>> - `Promise.prototype.catch` does neither.
>>
>> However the inconsistency within this trio seems pretty odd to me. I
>> suppose I would have expected them all to be as constrained as the most
>> constrained method needed to be for the sake of uniformity, given that they
>> constitute a single API. Conversely, if the goal was for each method to be
>> exactly as lenient as is possible, then `finally` seems to be
>> over-constrained; it seems like `C` could have just defaulted to `Promise`
>> in cases where `SpeciesConstructor` wasn’t applicable, making it as lenient
>> as `catch`.
>>
>> I wasn’t able to find prior discussion about this, though it’s a bit hard
>> to search for, so I may be missing it. Do these behaviors seem odd to
>> anyone else, or is it what you’d expect?
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to