Promises Consensus

Tab Atkins Jr. jackalmage at gmail.com
Thu Aug 1 11:26:34 PDT 2013


On Thu, Aug 1, 2013 at 11:04 AM, Mark S. Miller <erights at google.com> wrote:
> Between Tab's answer and mine, we see the two issues one might mean by
> "branding".

No, there's only the one concept. If you mean anything other than
"type detection via properties on the instance or its prototype
chain", then I don't think you're using the right word.  (If I'm
wrong, please correct me.)

Detecting thenables via the presence of a function-valued "then"
property on the object is, explicitly, branding.

> Anne's clarifying summary at
> https://mail.mozilla.org/pipermail/es-discuss/2013-August/032465.html speaks
> only in terms of "promise-likes". One of the things we need to settle is
> whether there is one predicate that applies to all the places in this
> summary that says "if ... promise-like". IMO we need to distinct tests --
>
> * isPromise for whether p is a promise and
> * isThenable for whether p is thenable.
>
> I would have the output-side tests for both .flatMap and .then be isPromise.
> I would also have the input side test for .then use isThenable. .flatMap has
> no input-side test, which is its point. A somewhat separable question is
> what these two tests are testing.
>
> The first hard reason why we must at least have an isPromise test on the
> output side of .then is that the promise already returned by .then must
> adopt this output promise without calling its .then method. Otherwise we
> lose support for lazy evaluation and for promise pipelining.

Right.  You can go as far as testing for the existence of a "then"
property and verifying that its value is a Function, but you can't
call it without breaking these qualities.  (For example, you can't
call it and verify that it doesn't immediately throw, perhaps because
it's a false-positive and doesn't like being passed null/functions as
arguments.)  If we have a reliable brand unrelated to registering
callbacks, that's even better.

> If the output side of .then is a non-promise thenable, it is a separate
> question whether it should be "adopted" by calling its .then method or
> whether it should be accepted. IMO it should be accepted. The isThenable
> test indicates something ugly is going on -- assimilation. With this AP2
> based design, we can isolate this ugliness to the input side of .then.

Hm, that works for me.  It *is* undetectable whether you do
adoption/assimilation on the output side or do wait-for-a-non-promise
on the input side, except via measuring timeing/ordering of when
.then() is called (which you shouldn't be doing, hopefully).  This
strategy also makes us somewhat more consistent in behavior when you
do a .then().flatMap() chain, between returning from .then() a real
promise and a thenable - if you do detection on the output side, the
latter case will fully assimilate, while the former will only adopt
(one level unwrapping).  If you defer detection, then the latter case
just accepts, which is closer to the former case's adoption.

> The second reason why the two tests need to be separate is that the output
> side of .flatMap cannot adopt simply by calling the output's .then method,
> because otherwise you'd often get exactly the recursive unwrapping that
> .flatMap is trying to avoid. In order to avoid this, it must test whether
> there is anything it can do to adopt other than calling .then.

Yup, .flatMap() needs to do detection for a real/explicitly-branded
promise.  (It can't detect for "flatMap-able", because that's meant to
be the generic monad operation.  Lots of different types of objects
can be monads in different ways, so the methods are *not* compatible
between types.)

~TJ


More information about the es-discuss mailing list