RE: Error objects in W3C APIs
From: Jonas Sicking [mailto:jo...@sicking.cc] > I agree. Creating hierarchies of error "types" seems fragile to me. > A better approach seems like having a short list of flat error types. In > cases where it might be useful to have a more specific error type, instead > include additional information on the error. So for example, rather than > having a NetworkResourceNotFound error, use NetworkError but add a property > which indicate what type of network failure. Not sure if that was what you > were proposing with the "proximate cause"? Yeah, basically. Although I question the utility of the types at all. As discussed in [the earlier thread about an InvalidOperationError][1], in practice bucketing errors into the short list of types isn't particularly helpful, I think. > (... a bunch of stuff I agree with regarding DOM errors.) I agree. > I'm not sure that there's a difference between these two. Or at least I don't > think there's a difference between the stuff that the DOM puts in .name, and > that ES puts in the classname. They express the same thing just in different > ways. Yeah. And the divergence is unfortunate, although not that big a deal, since it's kind of minor and in practice nobody really tries to use either the classname or name to distinguish, from what I see. > I don't think we should specify the exact string that goes into these > messages. It's good if implementations are free to add additional details if > they see developers struggling with something. > > But we could definitely do with more recommendations for implementations > about what information to include here. That would be cool in my opinion. The removal at [2] saddened me a bit. I wonder what other spec writers' perspectives are, given that nobody does so. Are we all just following accepted practice, but would be happy to switch? Or are there people that believe such guidance would be a bad thing? > I think a proposed solution would help clarify. > > For your Stream example above I would propose using an InvalidStateError but > give it a couple of properties so that code could understand what went wrong. > Maybe a property which contains "BaseWritableStream.write" to indicate that > that was the function that failed, and a second property which contains > "closing" or "closed" to indicate which wrong state was hit. This is > definitely a very unpolished proposal, but might illustrate something that > could work. Yeah, basically. My initial thought was some kind of identifier. E.g. ```js var closingError = new TypeError("nice human message"); closingError.cause = "wrote_while_closing"; var closedError = new TypeError("another nice human message"); closedError.cause = "wrote_while_closed"; ``` (The underscores could actually be replaced with spaces, but then it feels less identifier-ey. Kind of a strange thing when you think about it.) The idea would be that you try to maintain a globally-unique list of causes, so that people can match on exactly the cause they care about. Unlike `DOMException` names, you don't maintain a global list so that people can consult it and find a cause that matches; you maintain that global list so that people can consult it and *not* accidentally re-use a cause. It has all the normal fragility properties of a global registry, of course. Hmm. Your idea of indicating which method caused the failure is a very interesting one as well. I wonder if it is related to the error stack trace in a universal fashion. Certainly for user-space errors it is not, since if you refactor to call a helper function outside of your public API that throws an error, you'd want the "causer" to be the public API method, not the helper function. But it might be for web platform APIs, since in practice they hide their helper functions using self-hosted or C++ tricks. I've asked some Node people what info they think is most useful, since apparently they're starting to realize that they've built up some de-facto standards in Node core around this stuff and are thinking of making those more explicit and universal. It'll be interesting to see what they come up with. (Trevor Norris, if you're listening, feel free to chime in!) [1]: http://esdiscuss.org/topic/exception-type-for-invalid-operations [2]: https://github.com/whatwg/streams/commit/05369d410d89b34b001a2607d7dc7f7a0ed4af7e#diff-04c6e90faac2675aa89e2176d2eec7d8L859 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Syntactic parameters
When I take the ECMAScript grammar and expand its abbreviations as outlined in section 5.1.5, I get a grammar with lots of unreachable nonterminals (i.e., symbols that can't appear in any sentential form derived from Script or Module). For instance, consider StrictFormalParameters. With its parameters Yield and GeneratorParameter, it expands to 4 nonterminals: StrictFormalParameters StrictFormalParameters_Yield StrictFormalParameters_GeneratorParameter StrictFormalParameters_Yield_GeneratorParameter (I use underscores to make the resulting names easier to read.) In the unexpanded grammar, it's used in only 3 productions: 14.2: ArrowFormalParameters : ( StrictFormalParameters ) 14.3: MethodDefinition[Yield] : PropertyName[?Yield] ( StrictFormalParameters ) { FunctionBody } 14.4: GeneratorMethod[Yield] : * PropertyName[?Yield] ( StrictFormalParameters[Yield,GeneratorParameter] ) { FunctionBody[Yield] } The first two of these expand to productions that reference StrictFormalParameters and the last one expands to productions that reference StrictFormalParameters_Yield_GeneratorParameter. So StrictFormalParameters_Yield and StrictFormalParameters_GeneratorParameter are never referenced, and are thus unreachable. Is this intentional? Or should StrictFormalParameters have a "?Yield" subscript in the 14.3 and 14.4 productions? (And while we're in the neighborhood, should FunctionBody also have a "?Yield" subscript in those productions?) If not, why not? Similarly, I'm also wondering about the unreachability of Statement_Yield Declaration_Yield_Default BindingIdentifier_Default_Yield -Michael ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
> > > I really don't know what to do about this. > > A few facts: - Promises have a long history of controversy (I was there on the CommonJS list!) - The AP2 design was found acceptable (if not ideal) to all parties, providing us with a path through the controversy - Promises were a *very* late addition to ES6 With these facts at hand, the way forward seems clear: - Stick to AP2 like glue. - Sacrifice to deferment any non-fundamental part of the API which might re-ignite controversy. The committee failure mode of "do-both" should be stated more precisely as: "do-both at the expense of design coherency". AP2 is, in my opinion, a coherent design and therefore does not represent such a failure mode. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Just noting that with the infix ! syntax proposed for ES7, this would be e.respondWith(cache.get('foo') ! [0]) On Wed, Feb 5, 2014 at 4:44 PM, Tab Atkins Jr. wrote: > On Wed, Feb 5, 2014 at 3:51 PM, Brendan Eich wrote: > > Tab Atkins Jr. wrote: > >> But say you wanted to do something a bit more complicated. For > >> example, if the cache hits, but the result is a Promise, you might > >> want to show a throbber until the Promise resolves. Under the old > >> consensus, you could do this pretty easily - just do > >> "cache.get().chain(...)" and then operate on the result. Under the > >> new, you can't, because the cache promise won't resolve until after > >> the response promise resolves. We can't say "just hand-box", because > >> it breaks the easy pattern above when you*don't* want to do anything > >> > >> complicated - you have to .then() it and unbox there. > > > > Yeah, that would suck for the pretty one-liner. But is it really that > much > > more? Write it out and let's see A vs. B. > > e.respondWith(cache.get('foo').then(x=>x[0])) > > ...which doesn't look like much until you realize you have to repeat > the invocation on every single cache retrieval. (And remember to box > with [] on every cache set, or else the retrieval will error out.) > > ~TJ > -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 3:51 PM, Brendan Eich wrote: > Tab Atkins Jr. wrote: >> But say you wanted to do something a bit more complicated. For >> example, if the cache hits, but the result is a Promise, you might >> want to show a throbber until the Promise resolves. Under the old >> consensus, you could do this pretty easily - just do >> "cache.get().chain(...)" and then operate on the result. Under the >> new, you can't, because the cache promise won't resolve until after >> the response promise resolves. We can't say "just hand-box", because >> it breaks the easy pattern above when you*don't* want to do anything >> >> complicated - you have to .then() it and unbox there. > > Yeah, that would suck for the pretty one-liner. But is it really that much > more? Write it out and let's see A vs. B. e.respondWith(cache.get('foo').then(x=>x[0])) ...which doesn't look like much until you realize you have to repeat the invocation on every single cache retrieval. (And remember to box with [] on every cache set, or else the retrieval will error out.) ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Tab Atkins Jr. wrote: The APIs for Caches and dealing with responses are designed so that they work nicely together, acting the same way whether you pass a Response or a Promise. So you can often respond to requests with a simple "e.respondWith(cache.get('foo'))" and it Just Works®. Nice. But say you wanted to do something a bit more complicated. For example, if the cache hits, but the result is a Promise, you might want to show a throbber until the Promise resolves. Under the old consensus, you could do this pretty easily - just do "cache.get().chain(...)" and then operate on the result. Under the new, you can't, because the cache promise won't resolve until after the response promise resolves. We can't say "just hand-box", because it breaks the easy pattern above when you*don't* want to do anything complicated - you have to .then() it and unbox there. Yeah, that would suck for the pretty one-liner. But is it really that much more? Write it out and let's see A vs. B. There are various ways to work around this. One way is to auto-handbox: Heh, an oxymoron, like "Military Intelligence". But I know what you mean! we subclass Promise to CachePromise and hang a .chain() off of it which receives the actual value you stored in the map, while .then() silently unboxes and continues flattening as normal. Another way is to just guarantee that Cache promises never hand promises to their callbacks, and ensure that there are alternate ways to check if a Response is ready yet (maybe just forcing people to more explicitly track the Response promises directly, and make sure they're synced with the stuff in the Cache). Sure, there are longer ways to go, but they seem to require if-else's or similar. I still would like to see the A-B test. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 12:34 PM, Brendan Eich wrote: > Tab Atkins Jr. wrote: >> (Fixing it does involve magic, or >> subclassing, but those are things that can be done internally, rather >> than exposed to authors as terrible API.) > > Could you say a bit more? Do you mean APIs that defensively "hand-box" so > the user doesn't have to, with async map and its overloaded get return > value? So, to get a bit more concrete, the ServiceWorker spec introduces Cache objects, which are asynchronous maps. When you get/set/etc anything, you get back a promise for the result. ServiceWorker also has Response objects, which are what you're supposed to be putting into the Caches. Some parts of the API return Response objects directly, some return promises for Responses. So sometimes you'll be storing promises in the Cache. The APIs for Caches and dealing with responses are designed so that they work nicely together, acting the same way whether you pass a Response or a Promise. So you can often respond to requests with a simple "e.respondWith(cache.get('foo'))" and it Just Works®. So, that part's not affected by the promise change, because the whole point is that this part of the API unwraps things until it hits a Response. But say you wanted to do something a bit more complicated. For example, if the cache hits, but the result is a Promise, you might want to show a throbber until the Promise resolves. Under the old consensus, you could do this pretty easily - just do "cache.get().chain(...)" and then operate on the result. Under the new, you can't, because the cache promise won't resolve until after the response promise resolves. We can't say "just hand-box", because it breaks the easy pattern above when you *don't* want to do anything complicated - you have to .then() it and unbox there. There are various ways to work around this. One way is to auto-handbox: we subclass Promise to CachePromise and hang a .chain() off of it which receives the actual value you stored in the map, while .then() silently unboxes and continues flattening as normal. Another way is to just guarantee that Cache promises never hand promises to their callbacks, and ensure that there are alternate ways to check if a Response is ready yet (maybe just forcing people to more explicitly track the Response promises directly, and make sure they're synced with the stuff in the Cache). ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Tab Atkins Jr. wrote: (Fixing it does involve magic, or subclassing, but those are things that can be done internally, rather than exposed to authors as terrible API.) Could you say a bit more? Do you mean APIs that defensively "hand-box" so the user doesn't have to, with async map and its overloaded get return value? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 12:17 PM, Brendan Eich wrote: > Tab Atkins Jr. wrote: >> Note, though, that you can still have consensus*and* strong >> objections. Design-by-committee is still a failure mode to be >> avoided. > > Excellent point. Argues against "do both". Can't ditch .then/resolve given > library code interop constraint. That forces the conclusion from last week's > meeting. > > What do you think at this point? My Futures cereal next year will be > delicious and nutritious! I still think it's a mistake, and though most APIs won't care as they won't produce nested promises, some types of APIs *will* be negatively affected in hard-to-workaround ways. But I also respect champion-based design, and I've talked with Alex Russell who believes it's not as huge an impediment to some of our planned APIs as I believed. (Fixing it does involve magic, or subclassing, but those are things that can be done internally, rather than exposed to authors as terrible API.) ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Tab Atkins Jr. wrote: Note, though, that you can still have consensus*and* strong objections. Design-by-committee is still a failure mode to be avoided. Excellent point. Argues against "do both". Can't ditch .then/resolve given library code interop constraint. That forces the conclusion from last week's meeting. What do you think at this point? My Futures cereal next year will be delicious and nutritious! /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: async decision making (was Re: Promise.cast and Promise.resolve)
Alex Russell wrote: I'd rather we keep separate and conflict-prone APIs in separate objects, though. I'd rather we acknowledge that Promises are a library de-facto quasi-standard we are trying to codify, not green-field work where we can start over or "do both". Excited to hear someone else recognize this reality. Another realist! I will subscribe to your newsletter if you will buy my cereal! /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: async decision making (was Re: Promise.cast and Promise.resolve)
On Wed, Feb 5, 2014 at 12:00 PM, Brendan Eich wrote: > Edward O'Connor wrote: > >> Perhaps TC39 should consider adopting a similar policy. >> > > Policy, schmolicy :-P. > > (Presumably clocks with deadlines are required; consensus could break > afterwards, in spite of the formal rules.) > > Let's let our hair down a bit and get real here. We did not "declare > consensus" Thursday last week, in any formal or informal fashion. We knew > Andreas wasn't there. We heard his position articulated by Sam (who dialed > in). We knew most of what we now know. > > At this point we must forge async consensus. Is Andreas and anyone else > (I'm not singling him out; I sympathize and started on his/Sam's/Kevin's > "side" earlier last week) objecting doing so in a consensus-breaking way, > for sure? We should async-check this. > > Often one objects or finds a survivable fault in a consensus position, and > works to persuade others to overcome it. Sometimes this leads to > minimization (and over-minimization) and deferment of troublesome but > important bits (@medikoo on twitter reminds me we dropped .done after > June's big thread -- a semi-consensus deferment, I found from (re-)reading > a bunch of messages). > > If we really have broken consensus in the async sense, we will have to > back up to Kevin's fixup of AP2, as Mark suggests. I have no idea how this > will shake out. > > I'd rather we keep separate and conflict-prone APIs in separate objects, > though. I'd rather we acknowledge that Promises are a library de-facto > quasi-standard we are trying to codify, not green-field work where we can > start over or "do both". > Excited to hear someone else recognize this reality. > Is any of this persuasive to anyone? Dunno, you tell me. If DOM only > wanted .then/.resolve, you should join my "realist" camp :-P. > > /be > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: async decision making (was Re: Promise.cast and Promise.resolve)
Edward O'Connor wrote: Perhaps TC39 should consider adopting a similar policy. Policy, schmolicy :-P. (Presumably clocks with deadlines are required; consensus could break afterwards, in spite of the formal rules.) Let's let our hair down a bit and get real here. We did not "declare consensus" Thursday last week, in any formal or informal fashion. We knew Andreas wasn't there. We heard his position articulated by Sam (who dialed in). We knew most of what we now know. At this point we must forge async consensus. Is Andreas and anyone else (I'm not singling him out; I sympathize and started on his/Sam's/Kevin's "side" earlier last week) objecting doing so in a consensus-breaking way, for sure? We should async-check this. Often one objects or finds a survivable fault in a consensus position, and works to persuade others to overcome it. Sometimes this leads to minimization (and over-minimization) and deferment of troublesome but important bits (@medikoo on twitter reminds me we dropped .done after June's big thread -- a semi-consensus deferment, I found from (re-)reading a bunch of messages). If we really have broken consensus in the async sense, we will have to back up to Kevin's fixup of AP2, as Mark suggests. I have no idea how this will shake out. I'd rather we keep separate and conflict-prone APIs in separate objects, though. I'd rather we acknowledge that Promises are a library de-facto quasi-standard we are trying to codify, not green-field work where we can start over or "do both". Is any of this persuasive to anyone? Dunno, you tell me. If DOM only wanted .then/.resolve, you should join my "realist" camp :-P. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
async decision making (was Re: Promise.cast and Promise.resolve)
Hi, Mark wrote: > Unfortunately, just as Yehuda was not there in September and did not > agree to the consensus then, Andreas was not there on Thursday of > January and (above in this thread) does not agree to that consensus. > This indicates a different failure mode we should be concerned about. > Not everyone is at every meeting. If anyone absent from any meeting > can veto the hard-won consensus achieved by those who did attend, it > is hard to see how to make progress. At the W3C, both HTML and WebApps are chartered to only declare consensus asynchronously. This policy is in place precisely to avoid the scenario where key people are disenfranchised because they couldn't be at some F2F. Perhaps TC39 should consider adopting a similar policy. Ted ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Error objects in W3C APIs
On Feb 5, 2014, at 12:05 AM, Jonas Sicking wrote: > On Tue, Feb 4, 2014 at 9:49 AM, Domenic Denicola > wrote: >> From: es-discuss on behalf of Allen >> Wirfs-Brock >> >>> I've designed exception handling systems before and designed and worked >>> with complex exception hierarchies. My main caveat is that they are >>> somewhat of an attractive nuisance. It's easy to get into designing >>> beautiful classification hierarchies of dozens of different kinds of >>> exceptions, each with their own specific failure information that is >>> captured. In practice, I've found very little actual utility for them. >> >> My (more limited) experience is the same. > > I agree. Creating hierarchies of error "types" seems fragile to me. > The other problem (an extension of “fragile”) is error objects when more than one global object/realm is involved. Once you’re in that scenario type selection (e.g. making use of |instanceof|) can no longer be used in any meaningful way. —Oliver ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 11:17 AM, Mark S. Miller wrote: > Unfortunately, just as Yehuda was not there in September and did not agree > to the consensus then, Andreas was not there on Thursday of January and > (above in this thread) does not agree to that consensus. This indicates a > different failure mode we should be concerned about. Not everyone is at > every meeting. If anyone absent from any meeting can veto the hard-won > consensus achieved by those who did attend, it is hard to see how to make > progress. OTOH, without this dynamic, we might proceed despite strongly held > objections, which really is not consensus. Only our insistence on true > consensus has saved us from prior disasters like ES4. I really don't know > what to do about this. The W3C treats in-person consensus as only a weak consensus (at least, in most working groups, most of the time). Async consensus is the only one that's worthwhile, because it avoids problems like this, plus allows people more time to think through issues than they might get when put on the spot during a meeting. Note, though, that you can still have consensus *and* strong objections. Design-by-committee is still a failure mode to be avoided. ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 10:34 AM, Andreas Rossberg wrote: > On 5 February 2014 18:35, Domenic Denicola > wrote: > > 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). > > Just to be clear, that is not my recollection at all. > > I'm still puzzled where this interpretation of the consensus came in. > I was present in both respective meetings and don't remember this ever > being said. Nor does anybody else I asked so far. It's not in the > notes either. OTOH, I know that several participants have been under > the assumption that the consensus was to include all of AP2 in ES6. > That includes Mark, btw. > > Sorry to dwell on this, but this misunderstanding is what I find > particularly irritating. > I don't want to dwell on this either. Different people do indeed have different memories of both of the crucial meetings. And AFAIK, the notes do not adequately resolve the memory disputes. But just for the record, my memory regarding the memory-conflict issues are: At the end of May mtg, the consensus compromise was actually AP3. This rapidly fell apart due to discussion of its consequences on es-discuss, where AP2 was (correctly IMO) seen as strictly superior to AP3. At the end of Sept mtg, my memory of the state on entry to the meeting agrees completely with Domenic's. On exit, my memory is a) We had agreed to promote both the .then level and the .chain level to ES6. (This is probably the biggest disagreement among the memory of the attendees.) b) At the .then level, we agreed essentially to promises-unwrapping as it was at the time, which did one-level unwrapping of the output side of .then by use of internal properties. (Or what Domenic now characterizes as "by magic".) c) Domenic and Allen had talked about subclassing, and Domenic came up with a nice subclassing proposal that kept this "by magic" unwrapping. After the September mtg Yehuda did not attend the end-of-Sept mtg, and afterwards rejected the "by magic" unwrapping as hostile to subclassing goals I have yet to understand. Domenic responded by changing the output unwrapping of .then to use .then, which, as Kevin correctly points out, broke the AP2 consensus. However, at my urging, Domenic initiated a private thread with the main .chain level advocates, including IIRC Andreas, Sam, and Tab, to see if any objected to the switch to .then doing unwrapping by use of .then. I was privately shocked that none did. At this point, perhaps I did the community a disservice by staying silent, and not pointing out more forcefully to the .chain advocates why they should object to this switch. But since * they were not objecting, * the switch only harmed properties that they care about and none that I care about, * we knew of no way to restore the AP2 consensus and also achieve Yehuda's subclassing goals I did stay silent until this problem was independently noticed by Kevin and brought to my attention and (at my urging) Domenic's attention as well. Kevin's suggested a good way to meet all goals simultaneously. If we were still trying to do AP2, I think it would be worth considering: * On the output side of .then, still use some kind of nominalish type test to recognize whether the callback has returned a promise. * If it has, rather than use so-called "magic" to unwrap it one level, use that Promise's .chain. By calling the returned promise's .chain rather than .then, we preserve the one-level unwrapping of AP2. By calling its .chain rather than accessing its internal properties, we preserve the subclassing flexibility Yehuda wants. If we were still going to do the standards committee "do both" failure mode, Kevin's suggestion is the best way I've seen to reconcile all the conflicting demands. At Thursday of the end-of-January meeting, everyone there including the .chain advocates agreed to avoid the do-both compromise, and just adopt the .then level. This was an excellent decision, and one much better than I thought could be achieved. THE BIGGER ISSUE Unfortunately, just as Yehuda was not there in September and did not agree to the consensus then, Andreas was not there on Thursday of January and (above in this thread) does not agree to that consensus. This indicates a different failure mode we should be concerned about. Not everyone is at every meeting. If anyone absent from any meeting can veto the hard-won consensus achieved by those who did attend, it is hard to see how to make progress. OTOH, without this dynamic, we might proceed despite str
Re: Promise.cast and Promise.resolve
Sam Tobin-Hochstadt wrote: Just to be clear, that is not my recollection at all. For whatever the history is worth, this is also not my recollection of the consensus in May. Rashomon. Who is the Woodcutter? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 1:34 PM, Andreas Rossberg wrote: > On 5 February 2014 18:35, Domenic Denicola > wrote: >> 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). > > Just to be clear, that is not my recollection at all. For whatever the history is worth, this is also not my recollection of the consensus in May. In particular, in May my memory is that we decided on a _single_ constructor (ie, not both of "resolve" and "accept"), and that there wasn't any discussion or consensus for DOM to do something else. Sam ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 5 February 2014 18:35, Domenic Denicola wrote: > 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). Just to be clear, that is not my recollection at all. I'm still puzzled where this interpretation of the consensus came in. I was present in both respective meetings and don't remember this ever being said. Nor does anybody else I asked so far. It's not in the notes either. OTOH, I know that several participants have been under the assumption that the consensus was to include all of AP2 in ES6. That includes Mark, btw. Sorry to dwell on this, but this misunderstanding is what I find particularly irritating. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Specification styles
On 2/5/14 1:02 PM, Kevin Reid wrote: suppose that in windowB we previously evaluated function later(f, ...as) { setTimeout(function() { f(...as); }, 0); } and then in windowA we do proxyForB.later(proxyForB.postMessage, 5, "*"); then if I understand your description correctly, this would perform a postMesage from B's origin. Correct. In fact, you don't even need the setTimeout. Just this in windowB: function doNow(f, ...as) { f(...as); } and then windowA doing: proxyForB.doNow(proxyForB.postMessage, 5, "*") would have the same effect: the message would seem to come from windowB... In particular, what if "later" instead is something that is built-in, _not_ defined by the DOM, but has the effect of calling a function passed in? The way HTML5 attempts to define things right now is that if your "later" or my "doNow" is built-in as opposed to explicitly written in script then the message will come from window A. This is unfortunately gross, I agree... there needs to be a well-defined and preferably sensible decision about what happens upon something like: proxyForB.Array.prototype.forEach.call([5], proxyForB.postMessage); Right. That's what led to the concept of the script settings stack... The behavior here is in fact well-defined-ish, but it relies on this distinction between scripted and built-in functions. I believe the relevant text at http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#calling-scripts is this: When a JavaScript SourceElements production is to be evaluated, the settings object of the script corresponding to that SourceElements must be pushed onto the stack of script settings objects before the evaluation begins, and popped when the evaluation ends (regardless of whether it's an abrupt completion or not). Again, this doesn't so much make me happy; it's just the best people have come up with so far. In this case, since there is no SourceElements involved in Array.prototype.forEach (lots of handwaving involved in _that_ claim!) there would be no change to the script settings stack when forEach is invoked, so the message would be posted in the same way as if the forEach caller had directly invoked postMessage. Yes, this means that if you replace forEach with a scripted version you get different behavior. :( I'd love a consistent proposal that avoids that problem that browsers that aren't currently using any sort of membranes for their DOM are actually willing to implement. -Boris ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Domenic Denicola wrote: 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. Apologies for seeming to side with Kevin's "shenanigans", that's the wrong word. I shouldn't have cited it without noting how it usually implies bad intent. What I was reacting too, perhaps Kevin is as well, is the difficulty in getting something seemingly simple (as library code) standardized. And you're right, there was a lot of hard work to get to where we are. Thanks for all you've done. I am in no position to complain, having stayed away from the long promises threads over the last many months, mostly. But (and I fell for this too, no excuses) combining two conflicting APIs into one proposal was always a mistake. Andreas R. argues we can live with the over-wrapping in resolve, and seems to argue that my higher priority points (1, committee "do both" error; 2, .all etc. use .then not .chain) are either not problems or minor enough to live with. Ron Buckton just proposed a "do both" solution that is at least properly parameterized in the constructor, so combinators (2) work. But it's still a stinking optional state flag that forks runtime semantics and API reasoning chains (1), creating bug habitat and probably pleasing no one much. My "realism" argument seems strong, and your summary backs it: DOM was only using .then and .resolve, that's all they needed. That's all library Promise users use, in general (please correct me if I'm wrong). That is what Promises "are" in a real sense that constrains our standards efforts for ES6 and the DOM. HTH, and thanks again for all your work. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Specification styles
On Tue, Feb 4, 2014 at 9:21 AM, Boris Zbarsky wrote: > On 2/4/14 12:08 PM, Kevin Reid wrote: > >> Could not this be done while matching the above principle as follows? >> >> proxyForB, or more precisely the proxy for the function object >> (windowB.postMessage), does not actually invoke windowB.postMessage >> itself but a corresponding "post message from origin A" function. >> > > That's actually pretty complicated. Now you have two not-object-identical > representations of windowB.postMessage in the scope of windowB, no? The > current membrane in SpiderMonkey has a single per-global representation of > each object, for sanity's sake. As a simple example, consider this code in > window A: > > proxyForB.setTimeout(proxyForB.postMessage, 0, 5, "*"); > > What function object should the setTimeout implementation see? What > should happen when the timeout fires? You point out that this is indeed more complicated to get “right” than I had realized. I think it could still be done but things like setTimeout would have to be proxied in the same way. This arguably shows that the legacy policy is even more of a bad idea, though, because it breaks a property kind of like TCP (I don't know a name for it offhand, but it's related to the confused deputy). For example, suppose that in windowB we previously evaluated function later(f, ...as) { setTimeout(function() { f(...as); }, 0); } and then in windowA we do proxyForB.later(proxyForB.postMessage, 5, "*"); then if I understand your description correctly, this would perform a postMesage from B's origin. But why should it, just because there's an intervening user-defined HOF? In particular, what if "later" instead is something that is built-in, _not_ defined by the DOM, but has the effect of calling a function passed in? Whether or not one were to implement the mechanics in the way I propose, there needs to be a well-defined and preferably sensible decision about what happens upon something like: proxyForB.Array.prototype.forEach.call([5], proxyForB.postMessage); ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
From: es-discuss [mailto:es-discuss-boun...@mozilla.org] 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
RE: Promise.cast and Promise.resolve
Perhaps the unwrapping behavior of .then could be specified as an optional argument in the Promise constructor and .resolve methods. The default behavior is the current standard (i.e. .then auto-unwraps), but a different behavior could be specified: ``` var unwrapPromise1 = Promise.resolve(1); var unwrapPromise2 = Promise.resolve(unwrapPromise); unwrapPromise2.then(value => { assert(value === 1); // unwraps }) var flatPromise1 = Promise.resolve(1, "flat"); // or some other indicator of a monadic promise var flatPromise2 = Promise.resolve(flatPromise1, "flat"); flatPromise2.then(value => { assert(value === flatPromise1); }) var mixedPromise = unwrapPromise2.then(value => flatPromise2); mixedPromise.then(value => { assert(value === flatPromise1); // mixedPromise's unwrapping stops at flatPromise1 as it starts to unwrap flatPromise2 but stops unwrapping due to the defined behavior. return value; }).then(value => { assert(value === flatPromise1); // Since the previous .then was unwrapped into a "flat" promise, chained .then calls remain "flat". }); ``` Basically, unwrapping of .then stops once the monadic behavior is reached. This would work for Promise.all/Promise.race as well since they could respect this behavior. This has the added benefit of specifying Promises with a minimal API surface that auto-unwrap for ES6, but add optional arguments to the constructor and .resolve for ES7 or later to specify this behavior. As far as the Promise consumer is concerned, when they use .then, they will get the result the Promise producer expects them to get (the final underlying value in the common use case, or a possible promise in the monadic case). The API surface area does not change, and monadic promises become an opt-in for those that need the specialized case. Best regards, Ron > -Original Message- > From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of > Brendan Eich > Sent: Wednesday, February 5, 2014 7:46 AM > To: Quildreen Motta > Cc: Mark S. Miller; EcmaScript > Subject: Re: Promise.cast and Promise.resolve > > Quildreen Motta wrote: > > but as with other parts of JavaScript, the simpler, orthogonal > > primitives are not available for users to derive more complex > > functionality from easily. > > So true. JS is like a mini-toolkit of three-tool Swiss Army Knife > (functions) with constructor and closure tools as well as the big first-class > function edged tool; and super-caulk (objects) usable in a pinch as adhesive > as well as sealant. Kind of what you want when you are traveling light, in a > hurry running from zombies, no time to get a proper toolbox. > > Part of TC39's work has been decomposing some of the multi-tools into new > forms that do one thing well (arrow functions are my favorite in this regard). > But it is both hard to justify the effort, and actually a lot of effort, to > decompose fully in all cases. > > Still I agree with Paolo. If we had functional (even value-like, featureless, > then-able only via a special form, as in E) Futures, we could rebuild Promises > on them and let Promises remain the library they've always been. > > /be > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
I really regret that I couldn't be there on the last day of the meeting, and share the frustration I hear in this thread. I honestly have a hard time viewing this as a "consensus", if for nothing else than that I do not consent. :) For the record, let me repeat what I wrote in a private conversation with Brendan the other day: "This destroys the fragile consensus we had built last May, on which my and others' consent to moving forward with the spec work had been based since then. I am deeply concerned how a strategy of (largely) ignoring that consensus and creating a different precedent instead has been successful here. I don't buy the over-wrapping argument. I doubt it will be an issue in practice, for the same reason that recursive unwrapping is rarely needed in practice. The committee is prematurely optimising for the odd case out that can always be avoided by [careful] design. On the other hand, I'm far more concerned about the cost that the unwrapping and thenable-assimilation machinery imposes on the _common_ case, and which can _not_ be avoided (lacking .chain). A [separate] library would be dead on arrival, especially since the DOM and other libraries won't use it. It wouldn't even allow you to hygienicly wrap them, since you'd always have to go through the tainted operations. Anyway, we've discussed this briefly in the V8 team and decided to keep the .chain method in V8. We've heard enough voices, from inside and outside Google, who dislike the spec'ed API and much rather use chain. Unfortunately, you cannot polyfill it... " To add to that, I don't view the "double functionality" as a serious issue either. Chain is the (compositional) primitive, .then is a convenience abstraction on top. We have plenty of those in the lib. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Quildreen Motta wrote: but as with other parts of JavaScript, the simpler, orthogonal primitives are not available for users to derive more complex functionality from easily. So true. JS is like a mini-toolkit of three-tool Swiss Army Knife (functions) with constructor and closure tools as well as the big first-class function edged tool; and super-caulk (objects) usable in a pinch as adhesive as well as sealant. Kind of what you want when you are traveling light, in a hurry running from zombies, no time to get a proper toolbox. Part of TC39's work has been decomposing some of the multi-tools into new forms that do one thing well (arrow functions are my favorite in this regard). But it is both hard to justify the effort, and actually a lot of effort, to decompose fully in all cases. Still I agree with Paolo. If we had functional (even value-like, featureless, then-able only via a special form, as in E) Futures, we could rebuild Promises on them and let Promises remain the library they've always been. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Paolo Amadini wrote: I think the conclusion of using two distinct objects for that (with the other named FuctionalPromise, Future, or anything else) resolves the issue. Imperative Promise implementations may use those alternative primitives internally. +1 /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
I can understand the "you can't have your cake and eat it too" sentiment. Indeed, I do think that having `.then()` and `.chain()` in the spec is a mistake. The only thing that saddens me (and this also with some other parts of the spec, such as Object.create) is that `.then()` is not an orthogonal and composable primitive, it's a multi-method on top of simpler primitives, but as with other parts of JavaScript, the simpler, orthogonal primitives are not available for users to derive more complex functionality from easily. That is, these higher-level primitives provide support to a class of higher-level use cases, but not the necessary basis to support these use cases in general, and this is a bummer for modularity and re-usability. More so, I do think that just following de-facto standards without acknowledging that there might be "bugs" on them you want to fix when they are cheap to do so (i.e.: now, rather than after it becomes standard) really bothers me. Fixing libraries today, specially with a relatively new thing such as Promises/A+ is relatively "cheap." At any rate, I'm just venting now, and I agree that the spec should only support either one or the other (even if `.then()` is just a combinator, the addition of it on the specs would lead to unnecessary headache, since it doesn't compose cleanly with other constructs). I am just sad that the specs are once again favouring the higher-level, limited use cases. On 5 February 2014 12:39, Mark S. Miller wrote: > > > > On Wed, Feb 5, 2014 at 6:37 AM, Mark S. Miller wrote: > >> On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich wrote: >> >>> Kevin Smith wrote: >>> - Promise.cast is renamed to Promise.resolve (remove old Promise.resolve) - Keep then, reject chain (NOT DEFER, reject!) - Renaming .cast thus removes over-wrapping (always-wrap) deoptimization in old Promise.resolve 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". >>> >>> Can we regain consensus on the September status quo ante, minus any "do >>> both" half-hearted compromises that don't work? Mark, what do you think? >> >> >> I see no need to reopen this yet again. At this last meeting, we declared >> a new consensus, to keep the .cast and .then level, dispense with the >> .accept (previously renamed .resolve) and .chain level, and to rename .cast >> to .resolve. >> >> This kills the September AP2 consensus, in that we are no longer >> constraining the .then level's mechanics to be compatible with introducing >> (whether now or in the future) a .chain level. The September consensus was >> a compromise, in the "do both" mode that standards committees are tempted >> by. I have a deeper appreciation of those temptations now, having promoted >> it at the time. Given that we were trying to do both, Todd's AP2 was a >> wonderful way to minimize the pain. But I am now proud to see our committee >> once again rise above the "do both" failure mode. >> >> IMO, the most important argument against "do both" is that it would lead >> to perpetual confusion, as some libraries are written to the .then style >> and others are written to the .chain style. With AP2, these would live >> together as well as possible, but that's still not well. >> >> Regarding the comments in this thread, I haven't engaged since I have not >> seen any new points raised. All the old arguments are publicly archived. If >> you're about to repost a previously posted argument, please instead just go >> read the previously posted response. No one convinced anyone of very much >> that time, and repetition is unlikely to do better. >> >> The one remaining open issue for me is the means of flattening the output >> side of a .then operation. The end-of-september "consensus" flattened one >> level, but nom
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 6:37 AM, Mark S. Miller wrote: > On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich wrote: > >> Kevin Smith wrote: >> >>> >>> >>> - Promise.cast is renamed to Promise.resolve (remove old >>> Promise.resolve) >>> - Keep then, reject chain (NOT DEFER, reject!) >>> - Renaming .cast thus removes over-wrapping (always-wrap) >>> deoptimization in old Promise.resolve >>> >>> 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". >> >> Can we regain consensus on the September status quo ante, minus any "do >> both" half-hearted compromises that don't work? Mark, what do you think? > > > I see no need to reopen this yet again. At this last meeting, we declared > a new consensus, to keep the .cast and .then level, dispense with the > .accept (previously renamed .resolve) and .chain level, and to rename .cast > to .resolve. > > This kills the September AP2 consensus, in that we are no longer > constraining the .then level's mechanics to be compatible with introducing > (whether now or in the future) a .chain level. The September consensus was > a compromise, in the "do both" mode that standards committees are tempted > by. I have a deeper appreciation of those temptations now, having promoted > it at the time. Given that we were trying to do both, Todd's AP2 was a > wonderful way to minimize the pain. But I am now proud to see our committee > once again rise above the "do both" failure mode. > > IMO, the most important argument against "do both" is that it would lead > to perpetual confusion, as some libraries are written to the .then style > and others are written to the .chain style. With AP2, these would live > together as well as possible, but that's still not well. > > Regarding the comments in this thread, I haven't engaged since I have not > seen any new points raised. All the old arguments are publicly archived. If > you're about to repost a previously posted argument, please instead just go > read the previously posted response. No one convinced anyone of very much > that time, and repetition is unlikely to do better. > > The one remaining open issue for me is the means of flattening the output > side of a .then operation. The end-of-september "consensus" flattened one > level, but nominal typing and use of internal properties. > Should be *by* nominal typing and use of internal properties. > The current spec flattens using .then. The change was made to make > subclassing more flexible in ways I have yet to appreciate. But since we > are no longer trying to co-exist with .chain, now or in the future, I no > longer object to using .then for the output flattening of .then. I am fine > with the .then spec as currently written, in the context of the rest of our > decisions at the end of January meeting. > > >> >> /be >> > > > > -- > Cheers, > --MarkM > -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich wrote: > Kevin Smith wrote: > >> >> >> - Promise.cast is renamed to Promise.resolve (remove old >> Promise.resolve) >> - Keep then, reject chain (NOT DEFER, reject!) >> - Renaming .cast thus removes over-wrapping (always-wrap) >> deoptimization in old Promise.resolve >> >> 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". > > Can we regain consensus on the September status quo ante, minus any "do > both" half-hearted compromises that don't work? Mark, what do you think? I see no need to reopen this yet again. At this last meeting, we declared a new consensus, to keep the .cast and .then level, dispense with the .accept (previously renamed .resolve) and .chain level, and to rename .cast to .resolve. This kills the September AP2 consensus, in that we are no longer constraining the .then level's mechanics to be compatible with introducing (whether now or in the future) a .chain level. The September consensus was a compromise, in the "do both" mode that standards committees are tempted by. I have a deeper appreciation of those temptations now, having promoted it at the time. Given that we were trying to do both, Todd's AP2 was a wonderful way to minimize the pain. But I am now proud to see our committee once again rise above the "do both" failure mode. IMO, the most important argument against "do both" is that it would lead to perpetual confusion, as some libraries are written to the .then style and others are written to the .chain style. With AP2, these would live together as well as possible, but that's still not well. Regarding the comments in this thread, I haven't engaged since I have not seen any new points raised. All the old arguments are publicly archived. If you're about to repost a previously posted argument, please instead just go read the previously posted response. No one convinced anyone of very much that time, and repetition is unlikely to do better. The one remaining open issue for me is the means of flattening the output side of a .then operation. The end-of-september "consensus" flattened one level, but nominal typing and use of internal properties. The current spec flattens using .then. The change was made to make subclassing more flexible in ways I have yet to appreciate. But since we are no longer trying to co-exist with .chain, now or in the future, I no longer object to using .then for the output flattening of .then. I am fine with the .then spec as currently written, in the context of the rest of our decisions at the end of January meeting. > > /be > -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 05/02/2014 9.43, Brendan Eich wrote: > Can we regain consensus on the September status quo ante, minus any "do > both" half-hearted compromises that don't work? Mark, what do you think? For what it's worth, I've been planning to file a bug on GitHub before I saw the most recent conclusion, that dispelled my concerns. My conclusion, deriving from the explanations of the design that I received on this list (very informative by the way, thanks!) was that "Promise objects for imperative and functional use should be distinct". In fact, in the design I was concerned about, when calling a function that returns a Promise object generated by code that uses "imperative" promises (i.e. expects "then" to be used), a consumer that works with "functional" promises (i.e. uses "chain") cannot reasonably know which Promise type is returned, potentially leading to subtle bugs. Consider this scenario, with a typical documentation of an opaque imperative library: "The getResponse() method will return a Promise resolved with the response string." Will getResponse return a Promise(String) or a Promise(Promise(String))? It may actually return one or the other. To be sure about the type when used in a functional context, the promise will require unwrapping at the boundary between the two usage styles. Using the same object for both uses might lead to confusion and forgetting the unwrapping. I think the conclusion of using two distinct objects for that (with the other named FuctionalPromise, Future, or anything else) resolves the issue. Imperative Promise implementations may use those alternative primitives internally. Paolo ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Kevin Smith wrote: - Promise.cast is renamed to Promise.resolve (remove old Promise.resolve) - Keep then, reject chain (NOT DEFER, reject!) - Renaming .cast thus removes over-wrapping (always-wrap) deoptimization in old Promise.resolve 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". Can we regain consensus on the September status quo ante, minus any "do both" half-hearted compromises that don't work? Mark, what do you think? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
> > > - Promise.cast is renamed to Promise.resolve (remove old Promise.resolve) > - Keep then, reject chain (NOT DEFER, reject!) > - Renaming .cast thus removes over-wrapping (always-wrap) deoptimization > in old Promise.resolve > > 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. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Error objects in W3C APIs
On Tue, Feb 4, 2014 at 9:49 AM, Domenic Denicola wrote: > From: es-discuss on behalf of Allen > Wirfs-Brock > >> I've designed exception handling systems before and designed and worked with >> complex exception hierarchies. My main caveat is that they are somewhat of >> an attractive nuisance. It's easy to get into designing beautiful >> classification hierarchies of dozens of different kinds of exceptions, each >> with their own specific failure information that is captured. In practice, >> I've found very little actual utility for them. > > My (more limited) experience is the same. I agree. Creating hierarchies of error "types" seems fragile to me. A better approach seems like having a short list of flat error types. In cases where it might be useful to have a more specific error type, instead include additional information on the error. So for example, rather than having a NetworkResourceNotFound error, use NetworkError but add a property which indicate what type of network failure. Not sure if that was what you were proposing with the "proximate cause"? More on that below. I think the general direction that we've been heading lately has been pretty good. I.e. error types like NetworkError, QuotaExceededError are descriptive and have clear use cases for code to catch and handle. On the flip side, the DOM also has some overlapping errors that are too specific. IndexSizeError should simply have been RangeError, no need to use a separate exception because it was an index that was out-of-range, rather than some other type of argument. Then there's a bunch of errors which are unclear why you'd ever want to catch them at runtime. For example HierarchyRequestError, NotFoundError, NamespaceError and URLMismatchError is unclear to me why you'd ever want to catch. It seems useful to provide detailed information so that a developer is helped with understanding what went wrong, but that can be done through the .message property. TypeError is probably fine for many of these. Though I sort of hate its name and would be happy to see something more descriptive become available. > However, I think the utility that the DOM specs try to capture with their > errors is different than that captured by the exception hierarchy that one > might think of when looking at them. Let me set the stage: > > There seem to be a few possible properties of an exception that could be > varied depending on the situation: > > - The type. Typically this is very broad in ES, and in the DOM even more so > (everything is `DOMException`). In ES this is the same as the `.name` > property, but not in the DOM. > - The category. ES has no such concept, but DOM specs use the `.name` > property for this, with a variety of generic categories like > "InvalidStateException," "NetworkError," etc. [1] I'm not sure that there's a difference between these two. Or at least I don't think there's a difference between the stuff that the DOM puts in .name, and that ES puts in the classname. They express the same thing just in different ways. But that might not be relevant to your proposed solution. > - The human-readable message. This is never specified, from what I can see. I don't think we should specify the exact string that goes into these messages. It's good if implementations are free to add additional details if they see developers struggling with something. But we could definitely do with more recommendations for implementations about what information to include here. > - The proximate cause. By this I mean the exact situation or line of the > relevant spec that caused the error to be thrown. Every such cause should be > distinguishable, even if they belong to the same category. Usually there will > be a one-to-one correspondence between human-readable messages (or message > format strings, with appropriate placeholders) and machine-readable proximate > causes. I've seen this rarely, but some parts of Node.js use error codes for > this. > > I have not seen much attention paid to the "proximate cause" idea in the > wild. But I think it is perhaps the most important. Allen's point about > hierarchies being largely useless resonates with me on the type and category > level. That is, even the DOM's more fine-grained exception categorization is > not that useful if I am trying to recover from a specific scenario. Whereas, > the ability to specify specific situations to recover from would be much more > fruitful. > > For a great example of these levels, see [recent discussions on the streams > repo][2]. We have two situations: writing to a closing stream, and writing to > a closed stream. On an ES level, these would end up as both `TypeError`s, as > [discussed][3], with no further distinguishing information besides > implementation-defined `message`. Working on a DOM level would be no > different, I think: both would likely become `DOMException`s with `name` of > `"InvalidStateError"`. What we really want is a mach