I think the purpose of this proposal is to *forbid* module authors from making their Module Record namespace object thenable, since doing that causes confusion.
Setting a property on the function doesn't work when the "then" is inherited but the object still wants to be non-thenable; I think that the property has to go on the object - the thing that's not thenable - not on the "then" function itself, which wouldn't even have to be touched or looked at if the object is non-thenable. On Mon, Apr 16, 2018 at 1:15 PM, Ben Newman <benja...@cs.stanford.edu> wrote: > I agree with Tab that allowing developers to opt out of thenable behavior > is the only recourse now, but I don't think `Symbol.thenable` is the best > way to grant that power. > > In the case of module namespaces, since module authors cannot use > `Symbol.thenable` as the name of an export, there's no way to export a > `then` function while also opting out of thenable behavior by _exporting_ > `Symbol.thenable` as `false`. > > Instead, this proposal seems to imply that `Symbol.thenable` would have to > be added automatically to every module namespace object, which could be bad > news for module authors who (for whatever reason) actually wanted to export > a `then` function to make the namespace thenable. > > In general, whether or not we're talking about module namespace objects, > we're beginning to realize that the presence of a function-valued `.then` > property is not enough information to decide thenability in all cases, > though of course it must remain the default behavior because that's how > promise libraries have been written, and folks still do use promise > libraries instead of the native `Promise` (e.g. Bluebird). > > If an object does not have a `.then` function, then clearly it should not > be treated as thenable, so I wonder if there might be a way to disambiguate > individual `then` functions according to developer intent. Specifically, > what if the developer could set `object.then.able = false` to prevent > `object` from being treated as thenable, even though it has a > function-valued `then` property? In addition to checking for the presence > of a `then` method, `Promise` implementations would also need to check that > `then.able !== false` before treating the object as thenable. If the > `.able` property is absent from the `then` function (or truthy), the normal > thenability behavior would continue to apply. > > This proposal addresses the module namespace problem I described above, > since you can set `then.able = false` before exporting `then` from a > module. Note: because of function hoisting, it might be possible to get > access to the `then` function before `then.able` has been set, but I don't > think that's a problem for dynamic `import()`, since the module has to > finish evaluating before the `import()` promise resolves. > > While I think `then.able` is kinda cute (which is worth… something?), I > would also be totally open to alternatives like setting > `then[Symbol.thenable] = false`. The essential idea is to use properties of > the `then` function itself (rather than sibling properties of the object) > to indicate whether the object should be thenable. > > Ben > > His errors are volitional and are the portals of discovery. > -- James Joyce > > On Mon, Apr 16, 2018 at 1:36 PM, Tab Atkins Jr. <jackalm...@gmail.com> > wrote: > >> On Fri, Apr 13, 2018 at 6:00 PM, Isiah Meadows <isiahmead...@gmail.com> >> wrote: >> > I can't remember where, but I recall seeing this discussed elsewhere >> > (maybe in the TC39 meeting notes?) and the conclusion was basically >> > ¯\_(ツ)_/¯. I'm not convinced myself it's actually worth the extra >> > symbol just to make something not considered a thenable - all these >> > Promise libraries have been able to get away with it for this long; >> > what makes ES promises any different here? (Dynamic import is probably >> > the only possible case I can think of short certain proxies in terms >> > of things that could be considered thenables but shouldn't always.) >> >> Having a reserved property key is a big footgun; you *can't* reliably >> resolve a promise to an arbitrary object, because if the object >> happens to have a "then" key, it'll try to recursively resolve it. >> >> Userland may "get away with it" because "then" isn't a common key, but >> it's still a hassle, same as how __proto__ being a special key in JS >> causes problems with JSON usage - it's rare, but not unknown, and >> problematic because it's an obvious layering violation. >> >> > Worst case, you can just return a value that happens to have a promise >> > in a property, like in `{value: somePromise}` - nobody resolves that >> > except `co` IIRC. >> >> Note that this isn't about nesting promises (or even promise-likes) >> without recursive resolution, it's about nesting *thenables* into a >> promise without (attempted) recursive resolution, which is a much >> larger conceptual class: the presence of a "then" property says >> absolutely nothing about the type of an object. We've just been making >> a statistical judgement about the posterior probability of an object >> being promise-like based on the presence of a particular key, which is >> very dubious. >> >> I'm still strongly of the opinion that we messed this up; the reason >> we went with thenables was because it's how userland did it, and they >> were working under the constraints of a proliferation of promise-likes >> and the difficulty of userland type-testing; real Promise usage >> promulgated much quicker than the pessimistic estimates, tho, making >> the relative trade-off of "free" compatibility with promise-likes vs >> the layering violation of reserving a property name on every object >> forever much less favorable. We should have instead relied on the >> actual Promise type, with a Symbol escape-hatch opting a userland >> object into being a promise-like. Doing the reverse and letting >> objects opt *out* of being treated as promise-like is probably the >> most we can do at this point, unfortunately. Generic data-handling >> will just have to manually add such a Symbol to objects they're >> resolving to, which sucks but is better than the alternative of always >> using a wrapper object. >> >> (Note that having a "strictResolve" method won't help; it might >> prevent the precise promise you construct from recursing into the >> object, but if you then resolve *another* promise to that promise, >> it'll go ahead and try to recurse again. Maybe strictResolve() could >> auto-add the "I'm not a promise-like" symbol to the object it resolves >> to? That would be a bit more ergonomic for generic handling.) >> >> ~TJ >> _______________________________________________ >> 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 > >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss