- From: Mark S. Miller <erights@google.com>
- Date: Tue, 4 Jun 2013 08:42:45 -0700
- To: Domenic Denicola <domenic@domenicdenicola.com>
- Cc: Anne van Kesteren <annevk@annevk.nl>, Sam Tobin-Hochstadt <samth@ccs.neu.edu>, "Tab Atkins Jr." <jackalmage@gmail.com>, Sean Hogan <shogun70@westnet.com.au>, "www-dom@w3.org" <www-dom@w3.org>, "public-script-coord@w3.org" <public-script-coord@w3.org>, Alex Russell <slightlyoff@google.com>, es-discuss <es-discuss@mozilla.org>
- Message-ID: <CABHxS9jUz52U9BrsTdYoVvssBRjAouhabeHQj0UJKKv+jTrwDA@mail.gmail.com>
[+es-discuss] I just realized that this thread has occurred so far only on the wrong lists. Please let's proceed from here only on es-discuss. This is a language issue, not a browser issue. Let's please stop splitting the discussion between two communities. On Tue, Jun 4, 2013 at 8:32 AM, Mark S. Miller <erights@google.com> wrote: > On Tue, Jun 4, 2013 at 7:34 AM, Domenic Denicola < > domenic@domenicdenicola.com> wrote: > >> On Tue, Jun 4, 2013 at 9:48 AM, Anne van Kesteren <annevk@annevk.nl> >> wrote: >> >> > On Tue, Jun 4, 2013 at 8:55 AM, Sam Tobin-Hochstadt <samth@ccs.neu.edu> >> wrote: >> >> Thinking about this more, I'm now unsure why both `fulfill` and >> >> `resolve` are needed given the semantics of `.chain()` and `.then()` >> >> described below. >> >> >> >> In particular, if `.then()` chains recursively *before* calling the >> >> callback, then there's no difference between: >> >> >> >> Future.resolve(x).then(v => ...) >> >> >> >> and >> >> >> >> Future.fulfill(x).then(v => ...) >> >> >> >> even when `x` is a promise. The only way to observe this is with >> `.chain()`. >> >> >> >> Thoughts? >> > >> > I'm just going to try to repeat what you said here to make sure I >> understand. >> > >> > Promise.resolve(val) creates a promise of val, regardless of whether >> > val is a promise, has a callable then property, or anything like that. >> > (In that sense it is equivalent to Future.accept() today.) >> > >> > promise.then() keeps unwrapping promise's internal value until it no >> > longer has a callable then property at which point it invokes the >> > relevant callback passed to promise.then(). (Exact algorithm TBD after >> > broader agreement.) >> > >> > promise.chain() invokes its relevant callback with promise's internal >> value. >> > >> > promise.then() and promise.chain() return value (newPromise) is >> > resolved with the return value of their callbacks after it has been >> > unwrapped once. >> >> In general, this approach is extremely interesting. The shift from >> focusing on promise fulfillment and being in the three states of pending, >> fulfilled, and rejected to focusing on promise resolution and being in the >> two "fates" of unresolved and resolved is a big difference. But it is >> probably a win as it ends up eliminating the state concept almost entirely, >> making it just an emergent way of describing what happens with `then`. >> > > Agreed. This is a great direction. Thanks, Sam! > > Given this direction, I think the one operation that serves as both > Promise.resolve and Promise.fulfill should be the previously suggested > Promise.of. > > >> >> One point I am not entirely clear on is why there is *any* unwrapping of >> return values, as in the last step Anne describes. For consumption with >> `then` it seems to make no difference. I assume this is to match flatMap or >> bind semantics from other languages, so that if you use `chain` exclusively >> you match Haskell/Scala/et al. semantics? >> > > If you don't unwrap[1] at all, i.e., go with a .map-like treatment of > return values, rather than a .flatMap-like treatment, the difference is > unobservable to those who use .then exclusively, and the semantics seems > simpler, so this would seem to be a win. But the storage costs would be * > *HUGE**! Since the implementation can't in general tell whether a promise > will be observed with .chain or .then later, it would have to preserve each > level of nesting for .then calls nested in .then calls. This would lose the > flattening property that corresponds to being insensitive to how many > levels deep in a function call chain a value was returned from. The normal > tail-recursive promise loop pattern < > http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation> > would need to accumulate a level of nesting per iteration of the loop. > > >> >> I also think the name "chain" is pretty confusing, especially in light of >> already-existing terminology around promise chaining [1]. Is there >> precedence for it in other languages? flatMap seems clearest to me so far. >> >> [1]: https://www.google.com/search?q=promise+chaining >> > > > I agree. This terminology will lead to confusion: "To do promise chaining, > use .then. The .chain method doesn't support promise chaining." As for > .flatMap, I am indifferent, since I'm planning to avoid it myself. I leave > it to its advocates to suggest something unconfusing. > > > [1] I am always worried though when people use the term "unwrapping" as I > don't know what they mean. Does this mean flattening, assimilating, both, > or something else? What I mean here is to so one level of flattening. As > for whether .then should also do one level of assimilation if it sees a > non-promise thenable, I could go either way, but prefer that it should not. > The promise-cross-thenable case should be sufficiently rare that the cost > of the extra bookkeeping should be negligible. > > > -- > Cheers, > --MarkM > -- Cheers, --MarkM
Received on Tuesday, 4 June 2013 15:43:17 UTC