That seems reasonable, although I'm not sure of the value of that consistency. It'd have to be proven to be web-compatible - ie, if anyone was adding a `.then` to a primitive prototype, they might be relying on the current behavior of `.catch`.
On Fri, Jul 20, 2018 at 9:58 PM, Darien Valentine <[email protected]> wrote: > 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 <[email protected]> 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 <[email protected]> >> 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 >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >>
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

