Killing `Promise.fulfill`

Mark S. Miller erights at google.com
Wed Aug 21 17:55:17 PDT 2013


On Wed, Aug 21, 2013 at 5:33 PM, Tab Atkins Jr. <jackalmage at gmail.com>wrote:

> On Wed, Aug 21, 2013 at 5:12 PM, Mark S. Miller <erights at google.com>
> wrote:
> > On Wed, Aug 21, 2013 at 3:44 PM, Tab Atkins Jr. <jackalmage at gmail.com>
> > wrote:
> >>
> >> On Wed, Aug 21, 2013 at 3:36 PM, Domenic Denicola
> >> <domenic at domenicdenicola.com> wrote:
> >> > On Aug 21, 2013, at 18:31, "Mark S. Miller" <erights at google.com>
> wrote:
> >> >> Good idea. As a coercing function, a natural name is Promise.as(v1).
> >> >> Also,
> >> >> as a common coercer, brevity is a virtue.
> >> >
> >> > How about just `Promise`, following `String`, `Number`, `RegExp`,
> etc.?
> >> >
> >> > (I tend to agree with Tab that both #a and #b should return a new
> >> > promise.
> >> > But we do need an easy coercion function, as Mark emphasizes.)
> >>
> >> Yeah, that's the existing coercer idiom.  The other one that's close
> >> is Array.from().  It still always produces a new object, but that
> >> doesn't necessarily have to be a property of every class's usage.
> >>
> >> But I like just Promise(), sans "new".
> >
> >
> > Good. I like it too, and Allen's latest draft class semantics enables the
> > definition of classes that can do this reliably. But is there any way to
> > reliably polyfill this in ES5? It's not clear. For the std promise API,
> > given the urgency with which people want to use it *now*, I think this
> > polyfillability is important.
>
> Yes, why wouldn't it be?  The test for promise-ness can be done today,
> without special browser privilege, and distinguishing between
> `Promise(foo)` and `new Promise(foo)` is a trivial matter of testing
> the type of `this` inside the function.  (If it's instanceof Promise,
> you were called with new.  Otherwise, you weren't.  This isn't 100%,
> as people can fool you with Promise.call(), but that's not something
> you need to actually worry about, I think.)
>

This is an example of what I am worried about. Another is

    Object.create(p, {value: Promise}).Promise(....)

where p is a promise.

Perhaps it would help if, when we start to think "people can fool you
with..." it would help to substitute "an attacker can fool you with...".



>
> >>  There's no
> >> behavioral difference between resolving and accepting for .then(), so
> >> we don't need it there, and you already need to be careful that your
> >> value is wrapped in a promise for .flatMap() callbacks, so requiring
> >> the same for the resolver function when those are the semantics you
> >> want is fine with me.
> >
> > I did not understand this reasoning even though I like its conclusion.
> Could
> > you expand on this, perhaps with examples? Thanks.
>
> Okay.
>
> For .then(), you can't tell the difference between adopting and just
> fulfilling with a promise, because both will wait for the inner
> promise to fulfill before the outer promise fulfills.  So obviously
> you don't need a resolver function for "just wrap it" if you're using
> .then().
>
> For .flatMap(), there's a clear difference between the two.  However,
> we should probably engineer toward making things similar for the
> resolver and a .flatMap() callback.  In a callback, if you want to
> return a nested promise, you have to first wrap it in a throwaway
> promise (which will then get adopted away).  That is:
>
> p1.flatMap(x=>p2).flatMap(print) // prints whatever value p2 resolves to
> p1.flatMap(x=>Promise.of(p2)).flatMap(print) // prints p2 itself, not
> its resolved value
>
> Similarly, if you limit yourself to just the resolve/reject resolver
> functions:
>
> new Promise(r=>r.resolve(p2)).flatMap(print) // prints whatever value
> p2 resolves to
> new Promise(r=>r.resolve(Promise.of(p2))).flatMap(print) // prints p2
> itself, not its resolved value
>

Aha. Good I get it. Yes, I enthusiastically agree.


>
> On the other hand, if you allow the accept resolver function:
>
> new Promise(r=>r.accept(pw)).flatMap(print) // prints p2 itself, not
> its resolved value
>
> I'm fine with requiring the bit of extra work that's needed without
> accept, due to the symmetry - Resolver#resolve is exactly identical to
> returning from a callback, and Resolver#reject is exactly identical to
> throwing from a callback, but there's no way to duplicate
> Resolver#accept from a callback, and thus it's not clear that this
> functionality is actually needed.
>

Yes.


>
> >> We'll still need the class static for it, just not the resolver
> >> function.  I propose we quit with the synonyms, and use Promise.of()
> >> like I (and others) proposed a long time ago.  ^_^
> >
> > I do not love this but I do not object. +0.8 ;).
>
> Cool.  That means we get a decent naming precedent for the monad ops,
> and consistency with Array.of (which also happens to be a monadic
> lifter, if you limit yourself to calling it with only a single
> argument).
>

I agree that this naming analogy is a good thing. I raise my approval
magnitude to +1 ;).


>
> ~TJ
>



-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130821/69766b04/attachment-0001.html>


More information about the es-discuss mailing list