A Challenge Problem for Promise Designers

Tab Atkins Jr. jackalmage at gmail.com
Mon Apr 29 11:21:27 PDT 2013


On Mon, Apr 29, 2013 at 11:03 AM, Ron Buckton <rbuckton at chronicles.org> wrote:
> Thanks for the clarifications re: Future as a monad. My understanding of this is as follows (please correct me if I am wrong):
>
> * The expected result of the resolve/reject callbacks passed to Future#then is itself a Future.
> * If the result of the resolve/reject callbacks is not a Future it is logically lifted into a Future, by accepting the value on the Future that is the result of Future#then.
> * The Future result of the callback is merged into the Future returned Future#then then by chaining to either Future#then (Future#done?) of the callback result.
> * Given this, it is not usually necessary to "recursively unwrap" or "flatten" a Future. As a result Future#then should not flatten the result. This would preserve Future.accept(Future.accept(value)).then().then(F => /* F is Future(value) */).

All correct.  (Some of your precise mechanical details are probably
wrong, but you got all the important bits.)

> I can also agree that it is inherently unsafe to assimilate "thenables" for Future.resolve/FutureResolver#resolve, due to possible collisions with the property name on existing objects such as with casper.js. This kind of collision is the same rationale for having an @iterator symbol for iterators, though I wouldn't think the same resolution is likely the best result in this case. I am of the opinion that native Futures should only resolve native Futures (or possibly their subclasses). To assimilate you could have a Future.of (or possibly Future.from to match Array.from for "array-like" objects), which would assimilate "future-like" objects (i.e. "thenables"), but only via one level of unwrapping and not recursively.

I'm fine with the concept of using branding (via a symbol) to denote
that something should be treated like a future.  I'm also fine with
only allowing Promises and subclasses.  Whatever people decide is
better.

Domenic, after a lot of experience, thinks that the assimilation
procedure should be recursive (presumably "bottoming out" when it hits
a native promise).  I'm fine with that.  It does mean that if you need
to assimilate a thenable for a Casper object, it'll do the wrong
thing, but that's the price you pay for arbitrary library compat.  If
you know your foreign thenable is only a single layer, you can
safeguard its contents yourself, by chaining .then() and returning a
native Promise holding the value.  Then, the assimilation procedure
will "eat" the thenable, hit the Promise and adopt its state, and the
Casper object (or whatever) will be safe.

> I'm still concerned about cancellation, but will spin up another thread to hopefully spark some thoughtful discussion on the topic.

Go for it.  I have given some thought to it, and think I have a
reasonable model.

~TJ


More information about the es-discuss mailing list