- From: David Sheets <kosmo.zb@gmail.com>
- Date: Fri, 26 Apr 2013 16:45:38 +0100
- To: Domenic Denicola <domenic@domenicdenicola.com>
- Cc: Juan Ignacio Dopazo <dopazo.juan@gmail.com>, "public-script-coord@w3.org" <public-script-coord@w3.org>, es-discuss <es-discuss@mozilla.org>
On Fri, Apr 26, 2013 at 4:03 PM, Domenic Denicola <domenic@domenicdenicola.com> wrote: > From: David Sheets [kosmo.zb@gmail.com] > >> Why is there a semantic distinction between my thenables and your thenables? > > Because your thenables are not to be trusted! They could do pathological things like jQuery, or conceptually incoherent things like thenables-for-thenables. Sanitation at the boundary is the idea behind the resolve algorithm. But I am the programmer! If my own tools distrust me, all hope is lost. With the present special casing of own-promises, there can only ever be a single semantics (own-promises) even if I have an alternative semantics that I would like to use. >> If someone is using nested thenables, presumably they have a good reason.. Promises/A+ acknowledges this possibility by allowing own-promises to nest. > > Yes, but more importantly, it preserves the guarantees within a single library---whether they be allowing promises-for-thenables, or disallowing them. It destroys the guarantee that foreign libraries are in charge of their own resolution. Preserving foreign libraries' guarantees would require meddling with their values the *least* (1-level assimilation). > Q, when, RSVP, and others guarantee no promises-for-thenables. That is a great feature for consumers of those libraries, as has been emphasized many times in this thread (especially elegantly, I think, by David Bruant). That's a great feature for those programmers! If Q, when, and RSVP make that guarantee, they should enforce it by recursively resolving in *their* bind (or assimilation) operation, not relying on Promises/A+ or DOM Future to enforce it for them. > If there were no recursive foreign thenable assimilation, then promises-for-thenables could sneak into Q/when/RSVP promise systems, breaking the assumptions of consumers of those promises. After their recursively resolving bind? How? If they have a thenable and use their libraries' bind, their invariant is maintained. >> If we are interesting in constructing the "most standard" promises system, surely this system must grant other, foreign systems the same possibility of nesting own-promises without interference? > > No. Generally, foreign systems *must* be normalized, for security concerns if nothing else. What, specifically, are these security concerns? > Trying to accommodate foreign system semantics into your own promise system is a recipe for disaster. Mark can expand upon this more in detail, if you think it's an important point. It depends on what invariants are maintained, I believe. I've read quite a number of threads about this topic (including far too many pages of GitHub issues) and I've not, yet, come across something that indicates that delegating resolution to each own implementation breaks things. >> Could you point me to some code that needs dynamic flattening? > > From https://github.com/promises-aplus/promises-spec/issues/101#issuecomment-16657518 > >> ```js >> var promise = getDataFromServerUsingQ().then(function (data) { >> return $('.foo').animate('opacity', data.opacityLevel).promise().then(function () { >> return updateBackboneModelViaSomeThirdPartyLibraryUsingUnderscoreDeferred().then(function () { >> return tellServerThatTheUpdateSucceededUsingQ(); >> }); >> }); >> }); >> ``` This looks like a case for static resolution to me. Like this: ```js var promise = getDataFromServerUsingQ().then(function (data) { return Q($('.foo').animate('opacity', data.opacityLevel).promise()).then(function () { return Q(updateBackboneModelViaSomeThirdPartyLibraryUsingUnderscoreDeferred()).then(function () { return tellServerThatTheUpdateSucceededUsingQ(); }); }); }); ``` I favor this expression because it *explicitly* invokes Q's behavior early and every use of 'then' is Q's 'then'. It costs 6 more bytes. Do you have any examples where you *don't know* until runtime how many thenables are wrapped? >> If Q, as a proper Promises/A+ library, does recursive `[[Resolve]]`, this is a promise for undefined that will be rejected with the appropriate error if any of the operations failed. But if it did one-level unwrapping, this would be a QPFAUDPFAQPFU, and it would always fulfill---failure information would have to be manually extracted. If each of the wrapped promises also did one-level unwrapping, Q would not have to do dynamic unwrapping. If you use Q's assimilating constructor, you don't need dynamic unwrapping. If one-level unwrapping were the standard, all these libraries could interoperate *without* recursive resolution. If we're looking for the most flexible, straightforward, easiest, and future-proofed semantics, it seems to me that decreasing the amount of magic inside the abstraction is nearly always better. Does that make sense? David
Received on Friday, 26 April 2013 15:47:57 UTC