From: es-discuss [mailto:[email protected]] On Behalf Of Brendan Eich
> Kevin Smith wrote: >> So basically, since September, we've seen: >> >> - A design proposal which achieved "consensus" >> - A spec implementation which completely ignored that "consensus" >> - And now a third design, which also throws out "consensus" and has >> been implemented by precisely no-one >> >> And all of this over 200 to 300 LOC. >> >> These shenanigans are deeply disturbing. > > I agree. I kept my nose out of it until it was front-and-center on the last > day of the last TC39 meeting, and in context of threads here that were > pushing (I was on side with you) to add .chain. > > The design proposal in September did not have consensus, for real. That > proposal was changed after the September meeting (Mark has details). The > implementation in V8 then added .chain based on an understanding from the May > 2013 meeting (multiple, "Rashomon" views of consensus). > > There's still some concern about supporting Promise subclassing, too, but I > think it can be handled without controversy (I could be wrong). It entails > using the public-named methods (in case of overrides) consistently, and not > using internal methods or other such shortcuts some of the time. Basically > "always use .then". Like Mark, I've been mostly not engaging due to the lack of original points being raised. But I think it's important not to let Kevin's mischaracterization of the situation stand on the record, especially as it denigrates the hard work done by the many involved parties to come up with a workable promises design that meets all constraints, relegating it to such phrases as "shenanigans" and "200 to 300 LOC." The evolution of DOM and ES promises, and the related fragile consensuses, has been an involved process. Going back to the source documents, consider what the May AP2 proto-consensus really is: "Abashed Monadic Promises 2," from [Mark's presentation][1], page 18. Using modern terminology, this consisted of "resolve," "then," "accept," and "flatMap" (monads+promises, for short). The outcome of that meeting was that the DOM would proceed with standardizing the subset of AP2 that it needs, namely "resolve" and "then" (promises, for short). This resulted in the work at domenic/promises-unwrapping, which was targeted for the DOM. Coming to the September meeting, the documented that was distributed beforehand and presented was [this revision][2]. Committee members reviewed this document---some beforehand as per the agenda, some seemingly at the meeting---and declared it was a good subset to proceed with and would not prevent future problems if ES7 wanted to standardize monads+promises on top of the DOM's standard promises. Dave Herman made the bold suggestion that promises, as they were, would be useful for the module loader API, and that the spec was in good enough shape that we could move it from the DOM into ES6. This was accepted, and as such domenic/promises-unwrapping at the time was declared as September consensus for ES6 promises. My understanding of that meeting was that the September consensus was for ES6 promises, and that everyone in the room understood that. But I have heard conflicting accounts from people who were also in the room, who believed that the September consensus was for ES6 monads+promises. At the same time, others have told me that they understood the September consensus to be for promises, and would not have declared consensus if they were being told to agree on monads+promises. So we can already see how the "consensus" did not have consensus, for real, as Brendan puts it. That aside, let us consider Kevin's allegations about domenic/promises-unwrapping. At this point we have to say some words about the amount of work that goes in to producing a fully functioning spec, that respects all the constraints. Let those words be: it is nontrivial. Thus, it may come as no surprise that the version presented at the September meeting was not perfect. In particular, it had two large related problems: - It had not even the most naïve support for subclassing (cf. `Array` and `Date`, pre-ES6: the `Array.prototype.map` problem, the `Array.prototype.concat` problem, and the `(new (class extends Date)).getTime()` problem, all solved in ES6) - It created a new class of magic-objects with hidden, inaccessible, un-proxyable, internal state (cf. `Date`, still not solved in ES6) Both of these stemmed from, essentially, overuse of magic abstract operations and internal slots. This was yet another consensus-blocker, as discussions with several committee members revealed; another such object would never be allowed into ES6. So we had to do some work to reduce the reliance on magic, and move toward the usage of public APIs (viz. `then`), for accessing the state of other promises. This resulted in a few design revisions, largely based on the work of Andreas Rossberg in his proto-implementation of monads+promises, by choosing the promises subset and porting it from V8-JS with nominal type-checking to ECMASpeak with structural type-checking. At one point a long series of discussions---originally prompted by concerns about memory leaks---it was discovered that we could move all of the unwrapping logic into `then`, instead of putting half of it in `resolve` and half in `then`, which made `resolve` become an "accept" operation in reality. This is where the spec stands today, with `resolve` creating unobservable, memory-leaky promises-for-promises so that all the non-monadic behavior can be confined an over-complicated `then` algorithm. I welcome the simplification and performance benefits that will come with removing promises-for-promises and thereby simplifying `then`, and am excited to start producing mostly-red diffs on domenic/promises-unwrapping per [the plan][3]. In practice, *none* of the revisions made after the September meeting, including the latest ones decided on at the January meeting, have any practical consequence for the day-to-day usage of `new Promise()` plus `promise.then(...)`. They were observable changes, in the sense that you could send a specifically-crafted proxy through the algorithms, or override and instrument `Promise.prototype.then` appropriately, in order to discover them. And of course, they had an immensely positive impact on anyone who wanted to subclass `Promise`, or use AOP around promise methods, or use proxies in conjunction with promises, or use promises without skyrocketing memory usage, or even just wanted a predictable behavioral model for how promises interacted with themselves. But they did not impact "normal" usage. The amount of heat Kevin has piled on to promises-unwrapping, repeatedly, has been puzzling and unwarranted, but I have chosen mostly to set it aside, as the words of someone who did not care to understand the whole history and design constraints involved in writing this spec. The dismissive tone of the above confirms to me that this was the right approach. But I think it's important to outline, for the record, what has really been going on here, so that observers understand that no decisions were made lightly; no consensus was ignored; and the evolution of promises-unwrapping has been a careful, deliberate, and collaborative process. [1]: http://wiki.ecmascript.org/lib/exe/fetch.php?id=strawman%3Aconcurrency&media=strawman:promisesvsmonads2.pdf [2]: https://github.com/domenic/promises-unwrapping/blob/e316b8bf81180c6303b2dddf946f77aa8c10f38d/README.md [3]: https://github.com/domenic/promises-unwrapping/issues/91 _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

