W3C home > Mailing lists > Public > public-script-coord@w3.org > April to June 2013

RE: Promises: Auto-assimilating thenables returned by .then() callbacks: yay/nay?

From: Domenic Denicola <domenic@domenicdenicola.com>
Date: Fri, 3 May 2013 00:38:52 +0000
To: Tab Atkins Jr. <jackalmage@gmail.com>, Jonas Sicking <jonas@sicking.cc>
CC: "Mark S. Miller" <erights@google.com>, "public-script-coord@w3.org" <public-script-coord@w3.org>
Message-ID: <B4AE8F4E86E26C47AC407D49872F6F9F7EF720CB@SN2PRD0510MB360.namprd05.prod.outlook.com>
So, to preface, this entire reply is going to talk about promises-for-promises, not thenable assimilation. Sorry about taking over your well-intentioned thread on thenable assimilation, but I think there have been some points made here that need to be answered.

From: Tab Atkins Jr. [mailto:jackalmage@gmail.com]

> Can you elaborate on the complexity?  Based on the Futures spec, it seems to be pretty simple.

Not the spec complexity of course; fulfill is simpler than resolve in that sense. The complexity it introduces into the ecosystem, by allowing promises for promises to exist and gum up the works.

> This is, generically, the ability to compose Futures without having to worry about what's inside of them.  You've come up with one example.

I disagree. This is about a two-stage computation, which should be explicitly separated as such if desired (and it's not even clear it is desired). For example, instead of storing a FunctionFuture directly, the API could store a `{ functionToCompile }` object, so you do

indexedDB.get('storedFunction').then(function (storedFunction) {
  storedFunction.functionToCompile.then(function (compiledFunction) {
    // use compiledFunction here.

> The community of functional programmers has shown that, in general, this kind of thing is very often useful, and is captured in the abstract pattern of "monad".
> Mark has argued against nesting, based on his experience with E, where promises are featureless wrappers that disappear as soon as they're no longer needed. 

This again. We have a few problems here:

1. First, there's a double-standard here: you are arguing based on your experience with functional, strongly-typed languages, and telling us that applies, while at the same time telling us that Mark's experience with E doesn't apply.

2. You assume Mark is arguing based on experiences with E. That seems false: both Mark and the Promises/A+ community have worked extensively with *JavaScript* promises, and are telling you that promises-for-promises are bad news.

3. It would be helpful if you established your credibility in the area of functional, strongly-typed languages, so that we could be sure you were speaking from experience instead of just repeating what has appeared elsewhere. Just as a baseline, mind; I'm not accusing you of this, but just saying it would be helpful to set the stage for discussion so that we know where everyone is coming from.

4. I contend that solutions that work in strongly-typed, functional languages do not transfer well to JavaScript. There are a myriad of technical issues here we could discuss, from the existence of `throw`, to the possibility of returning different types, to side effects, but let's instead focus on the actual experimental evidence. Namely, every time I ask for an example of these hypothetical monad libraries in JS being used extensively, I get nothing but echoes. This indicates nobody is using such libraries in JavaScript extensively to the extent they are using promises, so perhaps we should be thinking about how promises work instead of how monads work?

   It might be the case that we are simply too early, and there is a JS monad renaissance in the wings. I sincerely doubt it, but even if that did happen, we'd need to wait at least a few years to see the kind of widespread use of monads as we do of promises. Maybe then we'd add a `flatMap` function to whatever promise standard exists at the time, to pave the existing cowpath as we are doing with `then` and promises.

  In short, you keep trying to conflate promises and monads, but it really just comes across as you trying to piggyback a related-but-different concept on top of the one we are all discussing. Like some sort of congressional rider bill, really. Let it go?

5. You have never address the problem of the identity function. If you cannot create promises for promises, then `var p2 = p.then(x => x)` is always an identity transformation; `p2` is always fulfilled with the same value as `p`. However, given `var f = Future.accept(Future.accept(5))`, you have that `var f2 = f.then(x => x)` is no longer an identity transformation; `f2` is fulfilled with `5`, whereas `f` is fulfilled with `Future.accept(5)`. To me this is an extremely clear example of how you are trying to port over semantics from monads to promises that do not fit with the promise framework, and more generally trying to port over semantics from strongly-typed languages to JavaScript, where you can't enforce the return type of the `onFulfilled` callback.

6. Finally, related to #5, having these unfortunate entities in the system requires guarding against them. I'd encourage you to take a look at Mark's latest smart contracts paper, and consider what would happen to the workings therein if promises-for-promises started flowing through the system. The identity function breakage certainly, but I would imagine much more.
> It occurs to me now that Domenic may have been doing the same "nested promises can't exist, so of course you (trivially) don't need recursive flattening for them" thing that Mark did earlier in this thread, in which case >_<.

Somewhat. I find the issue of what happens to nested promises very uninteresting, since they will hopefully not exist. I admit that if the monad camp does push them through the W3C, then we'll have to talk about their semantics, but I'd rather bite that bullet when we get shot with it (or something). 

Received on Friday, 3 May 2013 00:39:26 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 17:14:13 UTC