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

Reply via email to