A Challenge Problem for Promise Designers (was: Re: Futures)

Tab Atkins Jr. jackalmage at gmail.com
Fri Apr 26 08:25:40 PDT 2013

On Fri, Apr 26, 2013 at 3:19 AM, David Bruant <bruant.d at gmail.com> wrote:
> Le ven. 26 avril 2013 11:43:35 CEST, Andreas Rossberg a écrit :
>> On 26 April 2013 10:54, David Bruant <bruant.d at gmail.com> wrote:
>>> The Priority of Constituencies [1] asks us to be remain careful about
>>> theoretical standpoints. How does the theoretical part translates into
>>> helping users? authors (more than what I described at [2] which is
>>> derived
>>> from my own experience)? implementors? specifiers?
>>> I'm not saying the theoretical benefits don't exist, but I'd like to see
>>> how
>>> they translate in concretely improving my life as a developer using
>>> promises. I've explained the benefits I see for flattening from the dev
>>> point of view, I'd like to see the equivalent.
>> The argument is for regularity. On a global scale, regularity helps
>> the user, while exceptions, at best, are useful only locally -- an
>> observation that, unfortunately, is difficult to demonstrate with toy
>> examples.
> I see. To a large extent, it's also very hard to explain benefits to
> refactoring. I gave an abstract example, Mark gave a more concrete small
> example, but admittedly, none really capture the benefit I have experience
> in a medium-sized Node.js application.

I disagree with all those examples, though.  Not from a theoretical
level, but from a "those examples don't show what you want" level.

Unless I'm reading Mark's concrete example wrong, he didn't actually
show any nested promises at all - he showed a function that could take
a plain value or a promise, and wants to always treat it as a promise
(and return a promise).  That has nothing to do with nested promises,
and is already addressed by Futures anyway through Future.resolve().
(However, Mark hasn't been able to respond to this thread yet since my
last message, so he may point out something that I missed.)

Your abstract example was:

> If Future<Future<x>> can exist, then you'll have to write this
> boilerplate code in a lot of places:
>     f.then(function res(v){
>         if(Future.isFuture(v)){
>             v.then(res);
>         }
>         else{
>             // actual work with the resolved value.
>         }
>     })

I don't understand why this boilerplate code has to exist, or why it
does anything useful for you.  Fundamentally, your example seems to
show you having to react to a *badly-authored outside environment*,
where somebody fucked up and double-wrapped a value by *accident*.
This is exactly like arguing that Array#map needs to fully flatten, in
case people accidentally pass in [[1, 2, 3]].  Your scare-boilerplate
isn't even complete - if you're scared that the environment might be
broken and doing extra wrapping by accident, it might be doing three
or more levels of wrapping, too, so you've really got a problem on
your hands.

It's impossible for this to happen by accident unless someone's code
is broken.  I don't think this is an easy mistake to make, in the
first place, and if it is made, it should be fixed, not papered over
by the language.

The main reason people have given for this potentially happening is
authors mixing promise libraries, and the libraries not recognizing
each other's promises, so .then() doesn't properly unwrap the return
value of its callback.  This seems rare on its face (most authors
don't mix major libraries; authors on this list may be an exception),
will be much less common as the standard Futures crowd out
non-standard promises (not only will bespoke library promises be less
common, but whatever recognition mechanism Futures uses will be copied
by libraries, so the non-recognition problem will go away), and should
be fixed by an explicit bandage, such as Future.flatten() or
something, that can be applied by the author as necessary when
crossing library boundaries.  Breaking the regularity of the entire
feature for a rare, temporary, author-predictable library-interop
failure seems like a bad trade-off.

If you get stacked promises *on purpose*, then obviously you don't
want to break the feature by having .then() recursively unwrap.

I would *love* to see a concrete example of a nested promise problem
that's not a result of an authoring error (which seems hard to do on
its face - at least with Futures, it seems *difficult* to accidentally
double-wrap), a weird non-JS environment (like Dean Tribble's example,
which turned out to be invalid for JS promises and DOM Futures), or a
mixing of major libraries with bespoke promises that don't mutually
recognize each other (because this will go away reasonably fast now
that we have standardized Futures).


More information about the es-discuss mailing list