Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 11:38 PM, C. Scott Ananian wrote: [resending to list, original was sent from wrong address and got bounced] On Tue, Feb 18, 2014 at 11:12 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Feb 18, 2014, at 12:44 PM, C. Scott Ananian wrote: ```js var SubPromise = function(exec) { Promise.call(this, exec); ... }; Object.setPrototypeOf(SubPromise, Promise); SubPromise.prototype = Object.create(Promise.prototype); SubPromise.prototype.constructor = SubPromise; ``` Note that `SubPromise` inherits `Promise.@@create` and so this code will work fine in an ES6 environment. (Blame @domenic, he showed me that this should work!) ... It wouldn't work in an implementation where Promise was natively implemented according to the ES6 Promise spec but where 'new SubPromise(exec)' did not include a call to SubPromise.@@create. ... So the code above would work in a fully-compliant ES6 implementation. The question is: what should it do in the weird not quite ES6, but more than ES5 implementations that are shipping today. This isn't an ES6 spec issue, it's a challenge to implementors to provide forward-compatibility. Right, that's what I was trying to say. It all depends upon the new operator invoking @@create. It wouldn't work on an partial ES6 implementation where Promise.@@create was missing or where 'new' did not invoke @@create. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Sat, Feb 15, 2014 at 5:17 AM, Anne van Kesteren ann...@annevk.nl wrote: On Fri, Feb 14, 2014 at 10:50 PM, C. Scott Ananian ecmascr...@cscott.net wrote: Since both Chrome and FIrefox have plans to support Promises, feel free to suggest any changes to `es6-shim` which would improve compatibility. It looks like that at the moment the `es6-shim` implementation is more spec-compliant than either of the shipping implementations? In particular, we support subclasses. It will take a long time before browsers support subclassing in general as far as I can tell. I don't know where you're getting this from. @@create is the way classes and subclassing work in ES6, and any browser that wants to implement class syntax will need to deal with it. It may not be at the top of anyone's February 2014 hit-list, but I don't get any sense that classes are low priority for browser vendors either. -- http://annevankesteren.nl/ ___ 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
On 18 February 2014 10:43, Yehuda Katz wyc...@gmail.com wrote: On Sat, Feb 15, 2014 at 5:17 AM, Anne van Kesteren ann...@annevk.nl wrote: On Fri, Feb 14, 2014 at 10:50 PM, C. Scott Ananian ecmascr...@cscott.net wrote: Since both Chrome and FIrefox have plans to support Promises, feel free to suggest any changes to `es6-shim` which would improve compatibility. It looks like that at the moment the `es6-shim` implementation is more spec-compliant than either of the shipping implementations? In particular, we support subclasses. It will take a long time before browsers support subclassing in general as far as I can tell. I don't know where you're getting this from. @@create is the way classes and subclassing work in ES6, and any browser that wants to implement class syntax will need to deal with it. It may not be at the top of anyone's February 2014 hit-list, but I don't get any sense that classes are low priority for browser vendors either. Classes consist of many parts. The @@create hook only is relevant to enable subclassing of built-ins, and classes are useful without it. I think what Anne is alluding to is that for implementations, @@create probably is a pain to implement, and the part with the lowest benefit/cost ratio, and thus not particularly high on anybody's priority list. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Tue, Feb 18, 2014 at 10:29 AM, C. Scott Ananian csc...@cscott.netwrote: Yes, and I'm pointing out that you can subclass built-ins in a compatible manner even without the @@create hook, How? and hoping that we might see support for that (for Promises at least; maybe Map/Set as well). --scott -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
You can do so in the manner you were always able to in ES5, and you were able to do in ES6 before the introduction of @@create. However, what this means is that you now allow parastic inheritance again, which @@create was created to disallow. That is, you could have a MapPromiseWeakMap just by doing ```js var obj = {}; Map.call(obj); Promise.call(obj, function () {}); WeakMap.call(obj); ``` So such a solution isn't really maintaining the ES6 semantics, since it allows strictly more things than ES6 does. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 10:39 AM, Domenic Denicola wrote: You can do so in the manner you were always able to in ES5, and you were able to do in ES6 before the introduction of @@create. However, what this means is that you now allow parastic inheritance again, which @@create was created to disallow. That is, you could have a MapPromiseWeakMap just by doing ```js var obj = {}; Map.call(obj); Promise.call(obj, function () {}); WeakMap.call(obj); ``` So such a solution isn't really maintaining the ES6 semantics, since it allows strictly more things than ES6 does. No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Allen ___ 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
Yes. For these same reasons, Date.call(obj) already doesn't work in ES5. On Tue, Feb 18, 2014 at 10:54 AM, Allen Wirfs-Brock al...@wirfs-brock.comwrote: On Feb 18, 2014, at 10:39 AM, Domenic Denicola wrote: You can do so in the manner you were always able to in ES5, and you were able to do in ES6 before the introduction of @@create. However, what this means is that you now allow parastic inheritance again, which @@create was created to disallow. That is, you could have a MapPromiseWeakMap just by doing ```js var obj = {}; Map.call(obj); Promise.call(obj, function () {}); WeakMap.call(obj); ``` So such a solution isn't really maintaining the ES6 semantics, since it allows strictly more things than ES6 does. No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
From: Allen Wirfs-Brock al...@wirfs-brock.com No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Domenic Denicola wrote: Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. This is precisely the contentious issue, though. Should implementations be constrained to make Promises be normal objects with some internal slots initialized? If you subclass, you need the super's @@create to allocate the correctly shaped object, never mind setting the internal slots to default (undefined or nominal) values. Self-hosting a shim is nice, but it can overspecify. ES6 promises are not specified as self-hosted. Internal slots plus subclassability requires @@create. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
The same rationale would apply to Date, but making this change for Date would be a breaking change. For consistency, let's not pick and choose among builtins this way. We'll have @@create soon enough. On Tue, Feb 18, 2014 at 11:09 AM, Domenic Denicola dome...@domenicdenicola.com wrote: From: Allen Wirfs-Brock al...@wirfs-brock.com No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
Oh, for sure: I was not advocating a change in actual ES6. I was just explaining on Scott's behalf how it was possible to have subclassable polyfills before implementing @@create. Implementations could, in theory, implement subclassable promises before implementing @@create, via similar semantics. That is, they can choose between being standards non-compliant in one of two ways: 1. Non-subclassable, because no @@create. 2. Over-subclassable, because they allow parasitic inheritance. Eventually they will go for 3, just-plain-subclassable, once @@create is ready. But the question is what they want to do in the meantime. From: Mark S. Miller erig...@google.com Sent: Tuesday, February 18, 2014 14:16 To: Domenic Denicola Cc: Allen Wirfs-Brock; C. Scott Ananian; Brendan Eich; Yutaka Hirano; es-discuss@mozilla.org list Subject: Re: Promise.cast and Promise.resolve The same rationale would apply to Date, but making this change for Date would be a breaking change. For consistency, let's not pick and choose among builtins this way. We'll have @@create soon enough. On Tue, Feb 18, 2014 at 11:09 AM, Domenic Denicola dome...@domenicdenicola.commailto:dome...@domenicdenicola.com wrote: From: Allen Wirfs-Brock al...@wirfs-brock.commailto:al...@wirfs-brock.com No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 11:09 AM, Domenic Denicola wrote: From: Allen Wirfs-Brock al...@wirfs-brock.com No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. No, the whole point of @@create was to avoid that. In fact, initially I tried to specify something like that and implementors objected. The problem is that some implementations want to allocate different shaped object records for built-ins with specific internal slots and they can't dynamically change the size of the a normal object record that lacks those slots. It doesn't have anything to do with exotic objectness (which is about the behavior of the internal MOP methods) but instead about the memory layout of the objects. This was was discussed in detail 2+ years ago and there was consensus that @@create was the way to go. Now it's time to implement it. It probably isn't appropriate for implementors to unilaterally decide whether or not this is a low priority feature. However, I can understand how they might reach that conclusion if application and framework authors aren't vocal if they consider it to be a high priority feature. The reason I championed this capability was because I had heard years of complaining from JS developers about not being able to subclass Array, Date, etc. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Tue, Feb 18, 2014 at 11:23 AM, Allen Wirfs-Brock al...@wirfs-brock.comwrote: On Feb 18, 2014, at 11:09 AM, Domenic Denicola wrote: From: Allen Wirfs-Brock al...@wirfs-brock.com No, even if you removed the checks in Map and Promise and WeakMap that prevent them from trying to initialize an object that lacks the appropriate internal slots it still wouldn't work because obj does not have the internal slots necessary to support the built-in operations upon those objects and implementations commonly implement such objects in a manner that prevents the dynamic addition of such slots. The whole purpose of @@create is to allow implementations to allocate prior to invoking a constructor the correctly shaped object for built-ins. Well, but you could just move the internal slot initialization into the constructor itself (as Scott has done in his es6-shim promises). Unlike e.g. `Array`, the objects returned by `Promise[@@create]` are not exotic objects; they are simply normal objects with some internal slots initialized. So the movement of code between `@@create` and the constructor does not impact very much. No, the whole point of @@create was to avoid that. In fact, initially I tried to specify something like that and implementors objected. The problem is that some implementations want to allocate different shaped object records for built-ins with specific internal slots and they can't dynamically change the size of the a normal object record that lacks those slots. It doesn't have anything to do with exotic objectness (which is about the behavior of the internal MOP methods) but instead about the memory layout of the objects. This was was discussed in detail 2+ years ago and there was consensus that @@create was the way to go. Now it's time to implement it. It probably isn't appropriate for implementors to unilaterally decide whether or not this is a low priority feature. Hi Allen, I agree with the rest, but I'm puzzled by your statement above. ES6 is large. It has many pieces. Implementors cannot do everything first. TC39 does not state a priority order among ES6 features so implementors must. It has always been thus. However, I can understand how they might reach that conclusion if application and framework authors aren't vocal if they consider it to be a high priority feature. It is certainly valid and valuable for the community to provide feedback, to help implementors prioritize. But it is still the implementors that must make these priority order decisions. The reason I championed this capability was because I had heard years of complaining from JS developers about not being able to subclass Array, Date, etc. Allen -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 12:44 PM, C. Scott Ananian wrote: ps. I'm talking about this pattern in particular: ```js var SubPromise = function(exec) { Promise.call(this, exec); ... }; Object.setPrototypeOf(SubPromise, Promise); SubPromise.prototype = Object.create(Promise.prototype); SubPromise.prototype.constructor = SubPromise; ``` Note that `SubPromise` inherits `Promise.@@create` and so this code will work fine in an ES6 environment. (Blame @domenic, he showed me that this should work!) Just to be clear, you're saying that the above would work in ES5 with a polyfill implementation of Promise. Right? It wouldn't work in an implementation where Promise was natively implemented according to the ES6 Promise spec but where 'new SubPromise(exec)' did not include a call to SubPromise.@@create. It might work if the native Promise implementation diverged from the ES spec. and allowed Promise(exec) to be equivalent to new Promise(exec) when the this value is not a built-in promise object. But that would essentially be a non-standard extension that probably couldn't be subsequently killed. The purpose of standards for new features is to make sure that we don't have divergence out of the gate so let's push our implementors to avoid creating such divergence. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 2/18/14 2:51 PM, Allen Wirfs-Brock wrote: I'm also a bit concerned, that there may be a meme starting that it will be a looong time (years, if ever) before @@create is actually implemented so JS developers really shouldn't count on being able to use it if the foreseeable future. Such a meme could become a self-fullying prophecy. The longest pole on @@create from my point of view as a DOM implementor is that the setup for it is not quite compatible with how DOM constructors work (and have worked for many a year now) in Trident- and Gecko-based browsers. Specifically, Gecko and Trident allow a DOM constructor without new to create a new object of the right type (in ES5 terms, they're implementing a special [[Call]], not special [[Construct]], for DOM objects). Which means that before we can allow subclassing DOM objects we need to go through things like a deprecation period, use counters, etc, etc, to ensure that we're not breaking existing content that relies on the current behavior. Maybe we should make DOM constructors behave sort of like the Array constructor, of course... If we don't, then SpiderMonkey implementing @@create in the abstract will not automatically make the DOM subclassable in Gecko, and the latter cannot possibly take less than 5-6 months (to fix all the code we know depend on the current DOM constructor behavior, add telemetry and warnings, get reliable telemetry results back). That's if we discover that DOM constructors without new are not used in the wild. If they _are_ used, add more time for figuring out who's using them and convincing them to stop. Of course adding an extra internal slot to all DOM objects is not necessarily all that great either... Though maybe we have to do that no matter what to prevent double-initialization. All this doesn't affect subclassing of things like Date, of course. -Boris ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 1:12 PM, Boris Zbarsky wrote: On 2/18/14 2:51 PM, Allen Wirfs-Brock wrote: I'm also a bit concerned, that there may be a meme starting that it will be a looong time (years, if ever) before @@create is actually implemented so JS developers really shouldn't count on being able to use it if the foreseeable future. Such a meme could become a self-fullying prophecy. The longest pole on @@create from my point of view as a DOM implementor is that the setup for it is not quite compatible with how DOM constructors work (and have worked for many a year now) in Trident- and Gecko-based browsers. Specifically, Gecko and Trident allow a DOM constructor without new to create a new object of the right type (in ES5 terms, they're implementing a special [[Call]], not special [[Construct]], for DOM objects). Which means that before we can allow subclassing DOM objects we need to go through things like a deprecation period, use counters, etc, etc, to ensure that we're not breaking existing content that relies on the current behavior. In that case, i don't see why the DOM is a barrier to adding @@create to JS. The normal [[Construct]] behavior to specified to fall back to essentially ES5 behavior if an @@create isn't found. So it sounds to me that the above DOMs would just keep working as is if @@create+new is implemented as specified by ES6. The DOM classes wouldn't be subclassable out of the gate, but new things like Promises would be. Maybe we should make DOM constructors behave sort of like the Array constructor, of course... Do you really think you can deprecate exist call without new instantiation behavior? In ES6 every legacy constructor that had that behavior is specified to still have that behavior and always will. Are you saying that it isn't de-facto standard behavior and so there is a hope of getting rid of it. If we don't, then SpiderMonkey implementing @@create in the abstract will not automatically make the DOM subclassable in Gecko, and the latter cannot possibly take less than 5-6 months (to fix all the code we know depend on the current DOM constructor behavior, add telemetry and warnings, get reliable telemetry results back). That's if we discover that DOM constructors without new are not used in the wild. If they _are_ used, add more time for figuring out who's using them and convincing them to stop. SpiderMonkey implementing @@create is a prerequisite to making the DOM subclassable. But DOM use of @@create isn't a prerequisite for adding general JS @@create support. Of course adding an extra internal slot to all DOM objects is not necessarily all that great either... Though maybe we have to do that no matter what to prevent double-initialization. You don't necessary need a new slot to to use as an initialized flag. I most cases you can probably get away with using a not yet initialized token in some existing slot. All this doesn't affect subclassing of things like Date, of course. Write, we don't have to pre-boiled the ocean in order to start the beach fire... Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 2/18/14 4:34 PM, Allen Wirfs-Brock wrote: In that case, i don't see why the DOM is a barrier to adding @@create to JS. It's not, and I'm not quite sure where you thought I said it was I was talking about actual uses of subclassing for DOM objects. Maybe we should make DOM constructors behave sort of like the Array constructor, of course... Do you really think you can deprecate exist call without new instantiation behavior? Maybe. Unclear. Right now, WebKit (and Blink) doesn't support calling DOM constructors without new and never has. Trident and Gecko do and always (at least as far back as I can test) have. So we can deprecate it to the extent that web sites don't run different code in different browsers Some people are more worried about this than others, of course. Are you saying that it isn't de-facto standard behavior and so there is a hope of getting rid of it. It's unclear; see above. You don't necessary need a new slot to to use as an initialized flag. I most cases you can probably get away with using a not yet initialized token in some existing slot. While true, doing that requires per-object-type whack-a-mole that we don't really want to force DOM spec authors into -Boris ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 1:49 PM, Boris Zbarsky wrote: On 2/18/14 4:34 PM, Allen Wirfs-Brock wrote: You don't necessary need a new slot to to use as an initialized flag. I most cases you can probably get away with using a not yet initialized token in some existing slot. While true, doing that requires per-object-type whack-a-mole that we don't really want to force DOM spec authors into I think that could be handled generically in the WebIDL spec. You can specify it as if there was a per object initialized flag. But how that state is actually represented can be left to actual implementations to deal with. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Tue, Feb 18, 2014 at 3:34 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Of course adding an extra internal slot to all DOM objects is not necessarily all that great either... Though maybe we have to do that no matter what to prevent double-initialization. You don't necessary need a new slot to to use as an initialized flag. I most cases you can probably get away with using a not yet initialized token in some existing slot. Mmm. Well, sure, I think we can avoid bloating every Array to accomodate [[ArrayInitialisationState]], by optimizing for the case where it is true. But when you've got information, ultimately it has to be stored, somehow, somewhere. More to the point, this adds an axis to the configuration space of Array objects. That’s inelegant. It makes new kinds of bugs possible. Now that we're talking about extending the pattern to the whole DOM, it sounds worse than it did a few months ago. :-P Fight complexity creep! -j ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Feb 18, 2014, at 4:59 PM, Jason Orendorff wrote: On Tue, Feb 18, 2014 at 3:34 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Of course adding an extra internal slot to all DOM objects is not necessarily all that great either... Though maybe we have to do that no matter what to prevent double-initialization. You don't necessary need a new slot to to use as an initialized flag. I most cases you can probably get away with using a not yet initialized token in some existing slot. Mmm. Well, sure, I think we can avoid bloating every Array to accomodate [[ArrayInitialisationState]], by optimizing for the case where it is true. But when you've got information, ultimately it has to be stored, somehow, somewhere. More to the point, this adds an axis to the configuration space of Array objects. That’s inelegant. It makes new kinds of bugs possible. Now that we're talking about extending the pattern to the whole DOM, it sounds worse than it did a few months ago. :-P I believe that Array was the only ES6 built-in where I had to add such an initialization state internal slot. All others already had slots available that could do double duty for this flag. I suspect the same is true for most DOM objects. Such initialization checks have three purposes; 1)It prevents methods that depend upon internal state of built-ins from being applied to initialized instances. Array instances and methods actually doesn't have any such dependencies and none of its methods check for initialization. 2)Prevents potentially destructive double initialization. Generally, not an issue for Arrays but see use case 3 below 3)Used to distinguish calls to constructors for initialization (including super calls to the constructor) from calling the constructor as a function. The last one is the odd case. We need to be able to do do: class SubArray extends Array { constructor (...args) { this.foo = whatever; super(...args); }}; or even more explicitly class SubArray extends Array { constructor (...args) { this.foo = whatever; Array.apply(this, args); }}; (for most purposes these do the same thing and in particularly the super call and the Array.apply both call Array as a function in exactly the same way) But ES6 also says that calling Array as a function allocates and initializes a new Array object. So the challenge was how to extend Array (and other existing builtin or host object constructors) to continue to have their legacy called as a function behavior and still work as a super callable initializer. There were a few specific use cases that had to be considered (these all might exist in existing JS code): 1) Array(1,2,3,4) //should create a new Array and initialize it with 4 elements this is easy, the this value is undefined. So, the spec says that if the this value passed to the constructor is not an object, it must allocate a new instance and then initializes it. 2) var myNamespace = {Array: Array}; myNamespace.Array(1,2,3,4) //should create a new Array and initialize it with 4 elements The this value passed to Array will be the myNamespace object. We don't want to initialize it as an Array, but instead we need to allocate a new array instance. So, the spec. says that if the this value passed to the constructor is not an object that is not an Array , it must allocate a new instance and then initializes it. Array objects are identified (in the spec) by the present of the [[ArrayInitializationState]] internal slot but could alternatively be identified using some sort of an exotic array object brand or any other implementation specific branding of array instances. 3) Array.prototype.somethingNew = Array; var arr = new Array(5,6,7,8); arr.somethingNew(1,2,3,4) //should create a new Array and initialize it with 4 elements The this value pass to Array is the Array arr, so it is already branded as an Array but we don't what to reinitialize it and over-write its elements with the wrong values. So, the spec. says that if the this value passed to the constructor is branded as an Array and its [[ArrayInitializationState]] is true, the constructor must allocate a new instance and then initialize it. This works because [[ArrayInitializationState]] didn't exist in ES6. In ES6 the only way to get a handle on an uninitialized array is by directly calling Array[Symbol.create] or by intercepting such an uninitialized instance in a subclass constructor prior to a super call to the Array constructor. If this and other constructs didn't have new is optional constructor behavior, must of this would be unnecessary. That's why I generally recommend against people trying to define ES6 style class constructors that work without using new. It's too easy to screw up the above cases and not worth the effort for new code.
Re: Promise.cast and Promise.resolve
On 2/18/14 4:57 PM, Allen Wirfs-Brock wrote: I think that could be handled generically in the WebIDL spec. You can specify it as if there was a per object initialized flag. But how that state is actually represented can be left to actual implementations to deal with. Yeah, agreed. I came to the same conclusion earlier today while thinking about how to implement it. -Boris ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
[resending to list, original was sent from wrong address and got bounced] On Tue, Feb 18, 2014 at 11:12 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Feb 18, 2014, at 12:44 PM, C. Scott Ananian wrote: ```js var SubPromise = function(exec) { Promise.call(this, exec); ... }; Object.setPrototypeOf(SubPromise, Promise); SubPromise.prototype = Object.create(Promise.prototype); SubPromise.prototype.constructor = SubPromise; ``` Note that `SubPromise` inherits `Promise.@@create` and so this code will work fine in an ES6 environment. (Blame @domenic, he showed me that this should work!) Just to be clear, you're saying that the above would work in ES5 with a polyfill implementation of Promise. Right? Yes, it works in the current git HEAD of `es6-shim`. There are some checks to ensure that `SubPromise` inherits from `Promise`, which would also ensure that `@@create` is inherited (in the future). (See https://github.com/paulmillr/es6-shim/pull/218 for the grungy details.) It wouldn't work in an implementation where Promise was natively implemented according to the ES6 Promise spec but where 'new SubPromise(exec)' did not include a call to SubPromise.@@create. According to the ES6 spec, `new SubPromise(exec)` should include a call to `SubPromise.@@create`, right? As I read the spec, `new SubPromise(exec)` invokes `SubPromise.[[Constructor]](exec)` which would then invoke `Construct(SubPromise, [exec])`. In turn that would invoke `CreateFromConstructor(SubPromise)` which would fetch `SubPromise.@@create` which gets the inherited `Promise.@@create` and so would invoke `AllocatePromise(SubPromise)` to create the required `[[PromiseStatus]]` and other internal slots. So the code above would work in a fully-compliant ES6 implementation. The question is: what should it do in the weird not quite ES6, but more than ES5 implementations that are shipping today. This isn't an ES6 spec issue, it's a challenge to implementors to provide forward-compatibility. --scott -- ( http://cscott.net/ ) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Sat, Feb 15, 2014 at 3:17 AM, Anne van Kesteren ann...@annevk.nl wrote: It will take a long time before browsers support subclassing in general as far as I can tell. I'm not talking about the class system in general. I'm talking about the ES5+ code: ```js Promise.prototype.bind = function(newThis) { var SuperPromise = this._bindSuper || this.constructor || Promise; // create a new Promise subclass (this is less cumbersome in es6, sigh) var BoundPromise = function(exec) { return SuperPromise.call(this, exec); }; Object.setPrototypeOf(BoundPromise, SuperPromise); BoundPromise.prototype = Object.create(SuperPromise.prototype); BoundPromise.prototype.constructor = BoundPromise; BoundPromise.prototype._bindSuper = SuperPromise; BoundPromise.prototype.then = (function(superThen) { return function(f, r) { var ff = f f.bind(newThis); var rr = r r.bind(newThis); return superThen.call(this, ff, rr); }; })(BoundPromise.prototype.then); return newThis ? BoundPromise.resolve(this) : SuperPromise.resolve(this); }; ``` which is already useful in practice. It would be nice if the browsers would support Promise subclassing of this sort, in the (long?) interim without ES6 class syntax. --scott ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Fri, Feb 14, 2014 at 10:50 PM, C. Scott Ananian ecmascr...@cscott.net wrote: Since both Chrome and FIrefox have plans to support Promises, feel free to suggest any changes to `es6-shim` which would improve compatibility. It looks like that at the moment the `es6-shim` implementation is more spec-compliant than either of the shipping implementations? In particular, we support subclasses. It will take a long time before browsers support subclassing in general as far as I can tell. -- http://annevankesteren.nl/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Fri, Feb 7, 2014 at 11:50 AM, Anne van Kesteren ann...@annevk.nl wrote: I filed https://bugzilla.mozilla.org/show_bug.cgi?id=966348 on Gecko when the news broke. Mozilla can probably still make things in order before promises hit stable. To be clear, we fixed this. And we will be going ahead and shipping promises in Firefox 29. Too many dependencies at this point to hold of longer. -- http://annevankesteren.nl/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Fri, Feb 14, 2014 at 6:21 AM, Anne van Kesteren ann...@annevk.nl wrote: To be clear, we fixed this. And we will be going ahead and shipping promises in Firefox 29. Too many dependencies at this point to hold of longer. Since both Chrome and FIrefox have plans to support Promises, feel free to suggest any changes to `es6-shim` which would improve compatibility. It looks like that at the moment the `es6-shim` implementation is more spec-compliant than either of the shipping implementations? In particular, we support subclasses. At the moment we don't do any feature tests beyond does Promise exist in the global environment. For Map and Set we actually do some very specific bug-based tests to workaround old shipping implementations that aren't spec-compliant. So I'd also love to hear specifically about any bugs or missing features in your shipping implementation so that we can feature-test and workaround them. Finally, I have started `prfun` (https://github.com/cscott/prfun) as AFAIK the first es6-compatible promise package. That is, it assumes the presence of basic ES6 spec-compliant Promises and concentrates on adding features on top of that, using only the published API. It includes an implementation of `Promise.bind` using subclasses, in ES5-compatible syntax. It has a rather extensive test suite, borrowed from `bluebird`, `when`, and `q`. Feedback on `prfun` (including suggestions for better names!) is invited. --scott ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
On Sun Feb 9 07:30 PM, Brendan Eich wrote: Jonathan Bond-Caron wrote: Thoughts on adding options/flags Just say no. http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html This is a symptom. We are resisting the larger issue of do both or design-by- committee unioning or other such failure modes. Fair enough, would be nice to see an alternative to: https://github.com/apache/cordova-cli/blob/master/src/hooker.js#L155 If you multiply that pattern across many projects with different 'styles' of writing it, complexity really adds up. Promises.join([a,b,c]).run().then(...)// parallel Promises.join([a,b,c]).setExecution('serial').run().then(...) // serial? http://developer.android.com/reference/android/os/AsyncTask.html#SERIAL_EXECUTOR As I was writing this, I saw the async proposal: http://wiki.ecmascript.org/doku.php?id=strawman:async_functionss=async await would be king for serial execution of animations or file system tasks. It's all a bit confusing but going in an interesting direction, Cheers, J ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
On Fri Feb 7 12:14 PM, Tab Atkins Jr. wrote: From a user perspective, can someone explain what chain() does? .chain returns what is directly inside the promise, without doing any additional magic. This is different from .then, which flattens promises. For a more concrete example, assume that x is a PromisePromiseinteger. That is, it's a promise, holding a promise, holding an integer. x.chain(arg=arg is a PromiseInteger), x.then(arg=arg is an Integer). Thoughts on adding options/flags to then()? e.g. x.chain equivalent to x.then(promise, {unwrap: false}); Promises.all() could be similarly augmented to support serial execution. The api signatures become ~ Promise.prototype.then ( onFulfilled , onRejected|PromiseOptions , PromiseOptions ) Promise.all ( iterable , PromiseIterateOptions ) Defaults: PromiseOptions = { unwrap: true } PromiseIterateOptions extends PromiseOptions { serial: false } Don't have convincing use case but can pass options to then() during iteration: Promises.all([a,b,c], {unwrap: false}); ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 8 February 2014 07:37, Benjamin (Inglor) Gruenbaum ing...@gmail.comwrote: -- Forwarded message -- From: Brendan Eich bren...@mozilla.com To: Kevin Smith zenpars...@gmail.com Cc: Mark S. Miller erig...@google.com, EcmaScript es-discuss@mozilla.org Date: Fri, 07 Feb 2014 16:05:20 -0500 Subject: Re: Promise.cast and Promise.resolve A *working* implementation should be created and solutions to real-world use cases should be programmed using the design before any spec language is authored. Spec-language is apoor medium for communicating both design intent and programming intent. Yes, this. I just want to add my two cents on this part here. A lot of us are following this thread from the outside, being unable to keep track of all the meetings ambiguities and agreements and the such. Tracking it is hard with all the ambiguities and 'big words' people sometimes throw and unclear use cases. The way 'we' see it is: - Promises solve an interesting problem They do. And that problem is representing the eventual value of asynchronous computations, allowing you to compose them as usual. (there are different approaches to this too) - There are a number of promise libraries that are *working* implementations that solve real world use cases. They have evolved for several years _for_ those use cases. - I believe that was a big consideration for adding them to the specification to begin with. - Promise libraries _could_ have added some of the methods and alternatives discussed here but didn't. - Q is not the only library nor it is the 'de facto standard'. Kris is very knowledgeable but was not the only one building APIs. There are at least 4 more libraries that do promises (RSVP, When, Bluebird, kew, vow...). .chain , while very interesting is not very common to say the least. - Tens of thousands (probably more) of people have been using these libraries for years now. Well, promises are a fairly old concept, with several different implementations throughout the history of CompSci, and even in JavaScript land itself. `.chain` itself is not common because it doesn't need to have that name, but it is a common operation (`.then` encodes that operation, for example, but you can't control when it gets applied). As for working implementations of `.chain-able` promises, you can see: https://github.com/folktale/data.future#example, and https://github.com/fantasyland/fantasy-promises, although they are not Promises/A+, it should be easy enough to implement `.cast` and `.then` on top of those primitives. There are three things you want to do with a promise: - You want to sequence asynchronous computations, such that you can specify computations that depend on a particular value. This is what `.chain` does. - You want to transform the value of a computation, but the computation itself is synchronous. This is what `.map` does, and `.chain` can generalise `.map`. - You want to assimilate the result of a different promise. This is what `.cast` does. Unfortunately, Promises/A+ only provide you with a `.then` method, which does all of those things for you, but you can never control which of those gets applied. Thus, `.chain` is a more general approach, and `.then` can be easily derived from `.chain`. A specification should favour the general use cases to make it easy for people to write more specific computations in userland, instead of constraining the expressive power to particular higher-level use cases. This is what the discussion on Promises right now is about. I mean no disrespect to the hard work of the people here. I know everyone who is participating in the discussion here is putting a lot of time and effort to better the language and the community. However, from my complete outside it sounds like: - There is a working tested solution that evolved through usage and solving real problems over several years*. * - The committee is dictating a lot of changes for it. - Changes are based on new design goals and theoretical considerations like purity. I'm not saying there are no very good arguments for non-recursive assimilation and .chain (there are) , but they're still being dictated over existing library solutions. I was under the impression the goal is to adopt what works in practice as much as possible and not dictate solutions from the sky. If someone wants `a different API there is nothing preventing them from creating a library and doing that - then coming back with Hey, our solution works, we have 1000 dependencies on NPM or on second thought, that sounded very interesting but people are complaining about usage. One of the problems with just following existing solutions is that you'd also be copying the evolution mistakes and technical debts in those solutions. The committee **is** considering the existing solutions, and the use cases presented by people, which is a good thing. For example, for the asynchronous map use case
Re: Promise.cast and Promise.resolve
On Sat, Feb 8, 2014 at 2:57 PM, Quildreen Motta quildr...@gmail.com wrote: Well, promises are a fairly old concept, with several different implementations throughout the history of CompSci, and even in JavaScript land itself. `.chain` itself is not common because it doesn't need to have that name, but it is a common operation (`.then` encodes that operation, for example, but you can't control when it gets applied). As for working implementations of `.chain-able` promises, you can see: https://github.com/folktale/data.future#example, and https://github.com/fantasyland/fantasy-promises, although they are not Promises/A+, it should be easy enough to implement `.cast` and `.then` on top of those primitives. Phew! After that first sentence I thought I was getting a link to Liskov's paper(s) :) Both those libraries seem to have a low number of users, very few mentions and almost zero users in npm. I was not implying that it's impossible to implement chain, or monadic promises - I was implying very few people use them in JavaScript. Where, on the contrary people use the current model extensively in APIs. The debate from what I can tell is about standardizing something that exists but is not used nearly as much over something that exists and used extensively. There are three things you want to do with a promise: - You want to sequence asynchronous computations, such that you can specify computations that depend on a particular value. This is what `.chain` does. - You want to transform the value of a computation, but the computation itself is synchronous. This is what `.map` does, and `.chain` can generalise `.map`. - You want to assimilate the result of a different promise. This is what `.cast` does. Unfortunately, Promises/A+ only provide you with a `.then` method, which does all of those things for you, but you can never control which of those gets applied. Thus, `.chain` is a more general approach, and `.then` can be easily derived from `.chain`. A specification should favour the general use cases to make it easy for people to write more specific computations in userland, instead of constraining the expressive power to particular higher-level use cases. This is what the discussion on Promises right now is about. I'm not saying that `.chain` is a better or worse proposal here (or what I think at all). I'm talking about programmers in practice - those people in userland that are performing computations you speak of? They had a choice and they chose `.then`. Promise libraries such as Q (but not only) have been evolving for several years now. The way `.then` works was subject to change many times before but people in practice have found '.then' to be a simple and working solution. (For the record, when I think of .map I don't think of a synchronous computation - in fact I don't see that the fact the computation is synchronous in a promise chain is irrelevant - but again, this is not about _my_ opinion) One of the problems with just following existing solutions is that you'd also be copying the evolution mistakes and technical debts in those solutions. The committee **is** considering the existing solutions, and the use cases presented by people, which is a good thing. For example, for the asynchronous map use case, `.then()` is not usable short of adding plenty of special cases, and special cases don't compose cleanly. Standards are difficult because what you decide will shape the solutions that people write in the language for decades, standards evolve slowly, that's why you have less chances to make mistakes -- in a library you can make a mistake and promptly fix it in the next version, this is not true of standards. My problem with that paragraph is that promise libraries _have_ evolved for years. There are several libraries - Bluebird, Q, when, RSVP or any other promise library with _a lot_ of dependent libraries on NPM and more than a thousand stars on GH. They're all open source and At any point anyone could have: - Add 'chain' with a PR, explain why it's better and convince _any one of those_ maintainers why it should be added. I've seen work in Promise libraries several times. - Open an issue with convincing real life use cases and explain them - advocate .chain and get people to use it. I've seen this work in promise libraries several times and have done so myself. - Fork any one of them (most, if not all have permissive MIT licenses) and replace .then with .chain (or add it). It's also no problem to interop with existing A* libraries. - Build a new library and get users - I personally recently converted over 100 KLOC to use a promise library that didn't exist a year ago. I'd just like to add I did not make (at least intentionally) a single technical argument here. It's merely the process I'm concerned about. Choosing APIs that have no extensive use in the ecosystem over ones who do without first battle testing them concerns me.
Re: Promise.cast and Promise.resolve
On 8 February 2014 12:26, Benjamin (Inglor) Gruenbaum ing...@gmail.comwrote: On Sat, Feb 8, 2014 at 2:57 PM, Quildreen Motta quildr...@gmail.comwrote: One of the problems with just following existing solutions is that you'd also be copying the evolution mistakes and technical debts in those solutions. The committee **is** considering the existing solutions, and the use cases presented by people, which is a good thing. For example, for the asynchronous map use case, `.then()` is not usable short of adding plenty of special cases, and special cases don't compose cleanly. Standards are difficult because what you decide will shape the solutions that people write in the language for decades, standards evolve slowly, that's why you have less chances to make mistakes — in a library you can make a mistake and promptly fix it in the next version, this is not true of standards. My problem with that paragraph is that promise libraries _have_ evolved for years. There are several libraries - Bluebird, Q, when, RSVP or any other promise library with _a lot_ of dependent libraries on NPM and more than a thousand stars on GH. They're all open source and At any point anyone could have: - Add 'chain' with a PR, explain why it's better and convince _any one of those_ maintainers why it should be added. I've seen work in Promise libraries several times. - Open an issue with convincing real life use cases and explain them - advocate .chain and get people to use it. I've seen this work in promise libraries several times and have done so myself. - Fork any one of them (most, if not all have permissive MIT licenses) and replace .then with .chain (or add it). It's also no problem to interop with existing A* libraries. - Build a new library and get users - I personally recently converted over 100 KLOC to use a promise library that didn't exist a year ago. I'd just like to add I did not make (at least intentionally) a single technical argument here. It's merely the process I'm concerned about. Choosing APIs that have no extensive use in the ecosystem over ones who do without first battle testing them concerns me. It has been discussed at length before ( https://github.com/promises-aplus/promises-spec/issues/94), and continued in es-discuss. Specially because there are use cases for the standard library that are not covered by `.then` (Andreas has discussed them before). And again `.then` is just a special case of `.chain`, so the proposal that was being discussed was to give people `.chain` and `.then`, where `.then` would be written in terms of `.chain`. -- -- Quildreen (Soreλ\a) Motta (http://robotlolita.github.io/) *— JavaScript Alchemist / Minimalist Designer / PLT hobbyist —* ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Sounds both good in principle, and bad like waterfall. Waterfall is dead. Strike the waterfall part. Still, we end up with three artifacts: a design goals document, a prototype, and a spec. The design goals should be the first to stabilize, the spec should be the last. Would such goals have helped promises? I bet we would have fought over the goals, at best. At worst, we'd agree to vague goals and end up where we ended up. I think it would have helped. A formal set of goals is a measuring stick for the final design. If one of those goals is conform to AP2, then we can look at the final design and determine whether it, in fact, does conform to AP2. Furthermore, much of the meat of a design follows as a straight-line consequence of a well-stated set of goals. (See that doc I linked to for an example.) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Sat, Feb 8, 2014 at 8:11 AM, Kevin Smith zenpars...@gmail.com wrote: Sounds both good in principle, and bad like waterfall. Waterfall is dead. Strike the waterfall part. Still, we end up with three artifacts: a design goals document, a prototype, and a spec. The design goals should be the first to stabilize, the spec should be the last. There is no first or last. There is iteration, feedback, testing, iteration. Design should be swift, prototypes many, spec as a summary. Would such goals have helped promises? I bet we would have fought over the goals, at best. At worst, we'd agree to vague goals and end up where we ended up. I think it would have helped. A formal set of goals is a measuring stick for the final design. If one of those goals is conform to AP2, then we can look at the final design and determine whether it, in fact, does conform to AP2. Furthermore, much of the meat of a design follows as a straight-line consequence of a well-stated set of goals. (See that doc I linked to for an example.) All straight lines are illusions. Well-stated goals are goals rewritten to explain the results of iteration. But re-written, not ignored. Create goals, build to them, try it, re-create goals. No pure logic process can defeat reality: the promises discussion is built into the complexity of the problem and the currently available solutions. Hope for a technical breakthrough, plan for a compromise or a tough decision. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Resolving this would be much appreciated. Gecko recently turned on Promises in our nightly builds, and already branched to our aurora builds. I believe Chrome is in a similar situation. Chrome has shipped Promises, i.e. they are enabled by default on the current stable Chrome. So the situation is more serious for us. - 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 Sorry for knowing little about ES consensus, is this the final decision? Will you change it again? Thanks, On Wed, Feb 5, 2014 at 1:53 AM, Jonas Sicking jo...@sicking.cc wrote: On Wed, Jan 29, 2014 at 7:33 AM, Kevin Smith zenpars...@gmail.com wrote: It is, actually, more simplicity. The concept of `Promise.resolve` and `Promise.chain` is simpler than `Promise.cast` and `Promise.then` (i.e.: they represent orthogonal concepts, not complected). `Promise.cast` and `Promise.then` may be, arguably, *easier* to work with, from a user POV, since you don't need to make as many choices. I would argue that it would make more sense to write `cast` and `then` in terms of `resolve` and `chain`, however. But this seems to have already been decided. It does make more sense, and from my point of view it's not decided. What is decided is the AP2 design. That is: 1) promises are fully parametric and, 2) `then` recursively unwraps the *input* to its callbacks. For the sake of coherency (aka conceptual integrity), `then` needs to be written in terms of `chain`. This issue needs to be resolved ASAP, however, since promises are making their way into engines now. Resolving this would be much appreciated. Gecko recently turned on Promises in our nightly builds, and already branched to our aurora builds. I believe Chrome is in a similar situation. / Jonas ___ 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
On Fri, Feb 7, 2014 at 12:45 PM, Yutaka Hirano yhir...@chromium.org wrote: Sorry for knowing little about ES consensus, is this the final decision? Will you change it again? Yeah, some clarity would be nice. I filed https://bugzilla.mozilla.org/show_bug.cgi?id=966348 on Gecko when the news broke. Mozilla can probably still make things in order before promises hit stable. -- http://annevankesteren.nl/ ___ 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 11:17, Mark S. Miller erig...@google.com wrote: 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.) FWIW, I agree, but it's clearly at odds with Dominic's interpretation of that meeting. 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. To clarify, I may not have reacted directly (probably a mistake, but I considered .then to be too big a bag of magic anyway to really care about it per se, as long as flatMap/.chain was available as a clean and well-understood primitive, which I assumed would be the case -- as did Sam and Tab, I suppose). However, this question actually triggered me to have a closer look at the state of the spec (again), the outcome of which was my proposal for a refactoring. That refactoring based .then on .chain and pulled it from any of the core logic, thus avoiding the problems you seem to be alluding to, while still allowing subclassing. Dominic adopted much of that refactoring for the spec, but left out the central part, namely .chain and its use, because he assumed it wouldn't be relevant for ES6. 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 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. I agree that this is a general issue moving forward. We actually had several occasions where consensus flipped forth and back between meetings, which is a problem, especially when implementers want to move ahead with features. /Andreas ___ 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 5 February 2014 12:10, Alex Russell slightly...@google.com wrote: On Wed, Feb 5, 2014 at 12:00 PM, Brendan Eich bren...@mozilla.com 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. Alex, could you clarify your position a little bit? On one hand, you have repeatedly complained about the current spec, on the other hand you seem to be arguing for just adopting DOM reality. Can you say what this should consist of, from your point of view? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
However, this question actually triggered me to have a closer look at the state of the spec (again), the outcome of which was my proposal for a refactoring. That refactoring based .then on .chain and pulled it from any of the core logic, thus avoiding the problems you seem to be alluding to, while still allowing subclassing. For reference (since it was mentioned), my counter-proposal is here: goo.gl/3XzX9R and is basically just a minimization of Andreas's work. The only substantial difference is that `Promise.defer` is used as the subclass create a default tuple contract. (And less substantially, nominal type-testing is performed using a built-in symbol, rather than using internal slots.) I agree that this is a general issue moving forward. We actually had several occasions where consensus flipped forth and back between meetings, which is a problem, especially when implementers want to move ahead with features. If I may interject some opinions on process... I'm not sure how this fits in with the new post-ES6 process, but from this one outsider's point of view: - A formal set of design goals should be completed and agreed upon before design work is begun. The design goals form the basis of measurement and the champion(s) must be bound to them at all times. Any changes to the design goal document must be carefully reviewed in order to prevent churn. A detailed change-log is an obvious requirement. - A *working* implementation should be created and solutions to real-world use cases should be programmed using the design before any spec language is authored. Spec-language is a poor medium for communicating both design intent and programming intent. On a side note: it seems to me the the existence of the design champion, who by definition is deeply invested in the design process, implies the existence of its dual: the anti-champion, who is detached from the details of the design work and provides a vital holistic perspective. In a hierarchical organization this role would be taken on by the chief architect, I suppose, but in a committee you don't have one of those. : ) I feel that I have stepped into this role on occasion, much to the chagrin of various champions (apologies to Sam, Dave, and Domenic for any and all heat - nothing personal of course). ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
On Fri Feb 7 06:50 AM, Anne van Kesteren wrote: On Fri, Feb 7, 2014 at 12:45 PM, Yutaka Hirano yhir...@chromium.org wrote: Sorry for knowing little about ES consensus, is this the final decision? Will you change it again? Yeah, some clarity would be nice. From a user perspective, can someone explain what chain() does? Recently hit an issue with Q.all() vs serial execution of promises: https://github.com/jbondc/cordova-plugman/commit/ad2c74b3344c8899e8ede12827f7ca4637a01b6f#diff-9f06c51911da08ebd6400ff77d629c1eR309 chain() isn't mentioned here: http://wiki.ecmascript.org/doku.php?id=strawman:concurrency Promise.all() is included in the spec but not the case for serial execution: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.all-resolve-element-functions What seems like a preferred api / pattern from an ecma PoV to serially execute promises? e.g. Promise.serial(), Promise.ordered(), Promise.follow() Is it a common enough use case to be included in the spec? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
From: es-discuss es-discuss-boun...@mozilla.org on behalf of Jonathan Bond-Caron jbo...@gdesolutions.com What seems like a preferred api / pattern from an ecma PoV to serially execute promises? Promise.prototype.then https://github.com/kriskowal/q#sequences ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Fri, Feb 7, 2014 at 8:20 AM, Jonathan Bond-Caron jbo...@gdesolutions.com wrote: On Fri Feb 7 06:50 AM, Anne van Kesteren wrote: On Fri, Feb 7, 2014 at 12:45 PM, Yutaka Hirano yhir...@chromium.org wrote: Sorry for knowing little about ES consensus, is this the final decision? Will you change it again? Yeah, some clarity would be nice. From a user perspective, can someone explain what chain() does? .chain returns what is directly inside the promise, without doing any additional magic. This is different from .then, which flattens promises. For a more concrete example, assume that x is a PromisePromiseinteger. That is, it's a promise, holding a promise, holding an integer. x.chain(arg=arg is a PromiseInteger), x.then(arg=arg is an Integer). ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Kevin Smith wrote: If I may interject some opinions on process... Sure, it's es-discuss. Plus, you've earned your spurs. I'm not sure how this fits in with the new post-ES6 process, but from this one outsider's point of view: - A formal set of design goals should be completed and agreed upon before design work is begun. The design goals form the basis of measurement and the champion(s) must be bound to them at all times. Any changes to the design goal document must be carefully reviewed in order to prevent churn. A detailed change-log is an obvious requirement. Sounds both good in principle, and bad like waterfall. Waterfall is dead. Would such goals have helped promises? I bet we would have fought over the goals, at best. At worst, we'd agree to vague goals and end up where we ended up. - A *working* implementation should be created and solutions to real-world use cases should be programmed using the design before any spec language is authored. Spec-language is a poor medium for communicating both design intent and programming intent. Yes, this. On a side note: it seems to me the the existence of the design champion, who by definition is deeply invested in the design process, implies the existence of its dual: the anti-champion, who is detached from the details of the design work and provides a vital holistic perspective. Yes, the _advocatus diaboli_. We have plenty of those, though. Too many, at this point. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Le 07/02/2014 22:05, Brendan Eich a écrit : Kevin Smith wrote: - A *working* implementation should be created and solutions to real-world use cases should be programmed using the design before any spec language is authored. Spec-language is a poor medium for communicating both design intent and programming intent. Yes, this. A working implementation is a lot of work, even a polyfill. But tests. Very recent case in point : https://www.w3.org/Bugs/Public/show_bug.cgi?id=20701 It was a lot of words in English, lots of HTML5 spec vocabulary with very special and detailed meaning, I had lost track at some point, even with the spec-y summary by Bobby [1]. But then, he created tests and that was suddenly fairly easy to review [2]. It was fairly easy to point places that might be under-spec'ed and needed more tests. Tests are an excellent medium to discuss feature design. The current test suite leaves room for interpretation on a corner case? throw in a new test to disambiguate! On a side note: it seems to me the the existence of the design champion, who by definition is deeply invested in the design process, implies the existence of its dual: the anti-champion, who is detached from the details of the design work and provides a vital holistic perspective. Yes, the _advocatus diaboli_. We have plenty of those, though. Too many, at this point. woopsy... David [1] https://etherpad.mozilla.org/html5-cross-origin-objects [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=20701#c133 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
David Bruant wrote: Le 07/02/2014 22:05, Brendan Eich a écrit : Kevin Smith wrote: - A *working* implementation should be created and solutions to real-world use cases should be programmed using the design before any spec language is authored. Spec-language is a poor medium for communicating both design intent and programming intent. Yes, this. A working implementation is a lot of work, even a polyfill. But tests. Very recent case in point : https://www.w3.org/Bugs/Public/show_bug.cgi?id=20701 It was a lot of words in English, lots of HTML5 spec vocabulary with very special and detailed meaning, I had lost track at some point, even with the spec-y summary by Bobby [1]. But then, he created tests and that was suddenly fairly easy to review [2]. It was fairly easy to point places that might be under-spec'ed and needed more tests. Yeah, a warning to auto-didactic prose-heavy spec authors. Tests are an excellent medium to discuss feature design. The current test suite leaves room for interpretation on a corner case? throw in a new test to disambiguate! Tests++. Until they overspecify, then --. No silver bullets. More tests when in doubt. /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: 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
On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich bren...@mozilla.com 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 Wed, Feb 5, 2014 at 6:37 AM, Mark S. Miller erig...@google.com wrote: On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich bren...@mozilla.com 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
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 erig...@google.com wrote: On Wed, Feb 5, 2014 at 6:37 AM, Mark S. Miller erig...@google.com wrote: On Wed, Feb 5, 2014 at 12:43 AM, Brendan Eich bren...@mozilla.comwrote: 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
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
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
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 proto-implementation of monads+promises, by choosing the
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: Promise.cast and Promise.resolve
On 5 February 2014 18:35, Domenic Denicola dome...@domenicdenicola.com 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: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 1:34 PM, Andreas Rossberg rossb...@google.com wrote: On 5 February 2014 18:35, Domenic Denicola dome...@domenicdenicola.com 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 Wed, Feb 5, 2014 at 11:17 AM, Mark S. Miller erig...@google.com 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
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: 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
Re: async decision making (was Re: Promise.cast and Promise.resolve)
On Wed, Feb 5, 2014 at 12:00 PM, Brendan Eich bren...@mozilla.com 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)
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: 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: Promise.cast and Promise.resolve
On Wed, Feb 5, 2014 at 12:17 PM, Brendan Eich bren...@mozilla.com 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: (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:34 PM, Brendan Eich bren...@mozilla.com 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 PromiseResponse. 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: 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 PromiseResponse. 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 3:51 PM, Brendan Eich bren...@mozilla.com 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
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. jackalm...@gmail.com wrote: On Wed, Feb 5, 2014 at 3:51 PM, Brendan Eich bren...@mozilla.com 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
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
On Tue, Feb 4, 2014 at 11:53 AM, Jonas Sicking jo...@sicking.cc wrote: On Wed, Jan 29, 2014 at 7:33 AM, Kevin Smith zenpars...@gmail.com wrote: It is, actually, more simplicity. The concept of `Promise.resolve` and `Promise.chain` is simpler than `Promise.cast` and `Promise.then` (i.e.: they represent orthogonal concepts, not complected). `Promise.cast` and `Promise.then` may be, arguably, *easier* to work with, from a user POV, since you don't need to make as many choices. I would argue that it would make more sense to write `cast` and `then` in terms of `resolve` and `chain`, however. But this seems to have already been decided. It does make more sense, and from my point of view it's not decided. What is decided is the AP2 design. That is: 1) promises are fully parametric and, 2) `then` recursively unwraps the *input* to its callbacks. For the sake of coherency (aka conceptual integrity), `then` needs to be written in terms of `chain`. This issue needs to be resolved ASAP, however, since promises are making their way into engines now. Resolving this would be much appreciated. Gecko recently turned on Promises in our nightly builds, and already branched to our aurora builds. I believe Chrome is in a similar situation. Per Resolution ( https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-01/jan-30.md#conclusionresolution-3 ) - 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 Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Tue, Feb 4, 2014 at 10:55 AM, Rick Waldron waldron.r...@gmail.com wrote: Per Resolution (https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-01/jan-30.md#conclusionresolution-3) - 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 Okay, so this is discarding the previous consensus, right? Monadic promises are thrown out? This breaks async maps forever, then. :/ With the previous consensus, the result promise from an async map could be observed directly with .chain(), and it worked great regardless of what was stored inside the map. With only flat promises, if you store a promise in an async map and then try to retrieve it later, the error callback gets called if the key wasn't in the map *or* the key was in the map, but the stored value was a rejected promise. You have to spread your program logic over both callbacks to catch that case (or more likely, people will just write programs that break occasionally because they assumed that the reject branch of the AM.get() promise is only for failed lookups, as the documentation probably says). Similarly, if you store a forever-pending promise in the async map, it's impossible to ever retrieve it. Even just a long-pending promise will stall your program's logic while it waits, preventing you from updating UI when the map returns and *then* completing the operation when the stored promise finally resolves. The only way to get a working async map is to defensively store your values in a single-element array (or some other non-promise wrapper object) and unwrap them on retrieval. Pretending that all promises are identical identity-less wrappers that can be arbitrarily collapsed is such a mistake. _ Le sigh. ~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: On Tue, Feb 4, 2014 at 10:55 AM, Rick Waldronwaldron.r...@gmail.com wrote: Per Resolution (https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-01/jan-30.md#conclusionresolution-3) - 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 Okay, so this is discarding the previous consensus, right? Monadic promises are thrown out? Fundamental conflict between .chain and .then, on three levels: 1. Committee do both / union proposals smell and bloat -- this is a problem _per se_. 2. All the standard combinators call .then not .chain. 3. Including .chain requires always-wrapping resolve, observability trumps optimizability. There's really a 0 implicit in this: 0. Monadic vs. non-monadic is an exclusive or -- you can't have it all. This breaks async maps forever, then. :/ With the previous consensus, the result promise from an async map could be observed directly with .chain(), and it worked great regardless of what was stored inside the map. With only flat promises, if you store a promise in an async map and then try to retrieve it later, the error callback gets called if the key wasn't in the map*or* the key was in the map, but the stored value was a rejected promise. You have to spread your program logic over both callbacks to catch that case (or more likely, people will just write programs that break occasionally because they assumed that the reject branch of the AM.get() promise is only for failed lookups, as the documentation probably says). This does seem like a problem in the async map API, but I bet it can be solved without taking the hit of 1-3 above. Overloading get's return value is the root of the evil. Hand-boxing disambiguates the r.v. Similarly, if you store a forever-pending promise in the async map, it's impossible to ever retrieve it. Even just a long-pending promise will stall your program's logic while it waits, preventing you from updating UI when the map returns and*then* completing the operation when the stored promise finally resolves. This, I don't buy. You have to hand-box using {value: } or whatever. The only way to get a working async map is to defensively store your values in a single-element array (or some other non-promise wrapper object) and unwrap them on retrieval. Right, hand-box. That's the price of the XOR between Monadic and anti-Monadic promises, and anti-monadic already won in the library evolution of Promises. Pretending that all promises are identical identity-less wrappers that can be arbitrarily collapsed is such a mistake._ There are no great paths forward. I would like to make promises value objects, E-like. But it's too late. Promises happened, the DOM and ES6 need them, worse is better. You knew that already! /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Not sure if this is correct, but: This might actually be (perhaps accidentally) one step closer to allowing promises for thenables in a cleaner way *if* the need arises in the future. Since its impossible to create a promise for a promise now, it would be *theoretically* possible (at some point in the future) to just * introduce `Promise.of` (wraps thenables) * make `.then` unwrap true promises only once * make `resolve` cast thenables into promises that recursively unwrap thenables and be done. You'd have * `Promise.of` - wraps thenables, returns promises, wraps other values * `resolve` - converts thenables to recursively unwrapping promises, returns promises, wraps other values * `.then(f, r)` - for values returned by the handlers: recursively unwraps thenables, unwraps promises once, wraps other values After that, you could use `.then` in a monadic way, provided you remember to protect thenables with `Promise.of` (should not be a problem with typed compile-to-js languages). e.g. `resolve(Promise.of(thenable))` or `p.then(x = Promise.of(thenable))` You could also implement `.map` using `.then` and `Promise.of` Previously you'd have to make `resolve` and `Promise.cast` the same before making `.then` unwrap a single level. Alternatively, you'd have to introduce `.chain` and have a confusing dual API (chain/then, resolve/cast). On Tue, Feb 4, 2014 at 8:31 PM, Brendan Eich bren...@mozilla.com wrote: Tab Atkins Jr. wrote: On Tue, Feb 4, 2014 at 10:55 AM, Rick Waldronwaldron.r...@gmail.com wrote: Per Resolution (https://github.com/rwaldron/tc39-notes/blob/master/es6/ 2014-01/jan-30.md#conclusionresolution-3) - 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 Okay, so this is discarding the previous consensus, right? Monadic promises are thrown out? Fundamental conflict between .chain and .then, on three levels: 1. Committee do both / union proposals smell and bloat -- this is a problem _per se_. 2. All the standard combinators call .then not .chain. 3. Including .chain requires always-wrapping resolve, observability trumps optimizability. There's really a 0 implicit in this: 0. Monadic vs. non-monadic is an exclusive or -- you can't have it all. This breaks async maps forever, then. :/ With the previous consensus, the result promise from an async map could be observed directly with .chain(), and it worked great regardless of what was stored inside the map. With only flat promises, if you store a promise in an async map and then try to retrieve it later, the error callback gets called if the key wasn't in the map*or* the key was in the map, but the stored value was a rejected promise. You have to spread your program logic over both callbacks to catch that case (or more likely, people will just write programs that break occasionally because they assumed that the reject branch of the AM.get() promise is only for failed lookups, as the documentation probably says). This does seem like a problem in the async map API, but I bet it can be solved without taking the hit of 1-3 above. Overloading get's return value is the root of the evil. Hand-boxing disambiguates the r.v. Similarly, if you store a forever-pending promise in the async map, it's impossible to ever retrieve it. Even just a long-pending promise will stall your program's logic while it waits, preventing you from updating UI when the map returns and*then* completing the operation when the stored promise finally resolves. This, I don't buy. You have to hand-box using {value: } or whatever. The only way to get a working async map is to defensively store your values in a single-element array (or some other non-promise wrapper object) and unwrap them on retrieval. Right, hand-box. That's the price of the XOR between Monadic and anti-Monadic promises, and anti-monadic already won in the library evolution of Promises. Pretending that all promises are identical identity-less wrappers that can be arbitrarily collapsed is such a mistake._ There are no great paths forward. I would like to make promises value objects, E-like. But it's too late. Promises happened, the DOM and ES6 need them, worse is better. You knew that already! /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
Whoops, maybe scratch the monadic part - it would still be impossible to create a promise for a promise. It would however be possible to protect thenables. On Wed, Feb 5, 2014 at 2:17 AM, Gorgi Kosev gorgi.ko...@gmail.com wrote: Not sure if this is correct, but: This might actually be (perhaps accidentally) one step closer to allowing promises for thenables in a cleaner way *if* the need arises in the future. Since its impossible to create a promise for a promise now, it would be *theoretically* possible (at some point in the future) to just * introduce `Promise.of` (wraps thenables) * make `.then` unwrap true promises only once * make `resolve` cast thenables into promises that recursively unwrap thenables and be done. You'd have * `Promise.of` - wraps thenables, returns promises, wraps other values * `resolve` - converts thenables to recursively unwrapping promises, returns promises, wraps other values * `.then(f, r)` - for values returned by the handlers: recursively unwraps thenables, unwraps promises once, wraps other values After that, you could use `.then` in a monadic way, provided you remember to protect thenables with `Promise.of` (should not be a problem with typed compile-to-js languages). e.g. `resolve(Promise.of(thenable))` or `p.then(x = Promise.of(thenable))` You could also implement `.map` using `.then` and `Promise.of` Previously you'd have to make `resolve` and `Promise.cast` the same before making `.then` unwrap a single level. Alternatively, you'd have to introduce `.chain` and have a confusing dual API (chain/then, resolve/cast). On Tue, Feb 4, 2014 at 8:31 PM, Brendan Eich bren...@mozilla.com wrote: Tab Atkins Jr. wrote: On Tue, Feb 4, 2014 at 10:55 AM, Rick Waldronwaldron.r...@gmail.com wrote: Per Resolution (https://github.com/rwaldron/tc39-notes/blob/master/es6/ 2014-01/jan-30.md#conclusionresolution-3) - 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 Okay, so this is discarding the previous consensus, right? Monadic promises are thrown out? Fundamental conflict between .chain and .then, on three levels: 1. Committee do both / union proposals smell and bloat -- this is a problem _per se_. 2. All the standard combinators call .then not .chain. 3. Including .chain requires always-wrapping resolve, observability trumps optimizability. There's really a 0 implicit in this: 0. Monadic vs. non-monadic is an exclusive or -- you can't have it all. This breaks async maps forever, then. :/ With the previous consensus, the result promise from an async map could be observed directly with .chain(), and it worked great regardless of what was stored inside the map. With only flat promises, if you store a promise in an async map and then try to retrieve it later, the error callback gets called if the key wasn't in the map*or* the key was in the map, but the stored value was a rejected promise. You have to spread your program logic over both callbacks to catch that case (or more likely, people will just write programs that break occasionally because they assumed that the reject branch of the AM.get() promise is only for failed lookups, as the documentation probably says). This does seem like a problem in the async map API, but I bet it can be solved without taking the hit of 1-3 above. Overloading get's return value is the root of the evil. Hand-boxing disambiguates the r.v. Similarly, if you store a forever-pending promise in the async map, it's impossible to ever retrieve it. Even just a long-pending promise will stall your program's logic while it waits, preventing you from updating UI when the map returns and*then* completing the operation when the stored promise finally resolves. This, I don't buy. You have to hand-box using {value: } or whatever. The only way to get a working async map is to defensively store your values in a single-element array (or some other non-promise wrapper object) and unwrap them on retrieval. Right, hand-box. That's the price of the XOR between Monadic and anti-Monadic promises, and anti-monadic already won in the library evolution of Promises. Pretending that all promises are identical identity-less wrappers that can be arbitrarily collapsed is such a mistake._ There are no great paths forward. I would like to make promises value objects, E-like. But it's too late. Promises happened, the DOM and ES6 need them, worse is better. You knew that already! /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
1. Committee do both / union proposals smell and bloat -- this is a problem _per se_. Irony: .then() does both things and there's no way to stop it from doing both. The do both committee is actually not wanting both, it wants to only do one thing. We insist, we demand on having a way to NOT do both: we want .chain, and those who want .then can keep recursing through .chain while it's still a promise: that's your .then. Irony aside, this is really a very handwavy thing. How much bloat is it? Is the smell going to effect the neighbors? Is this like Fabreeze level spec smell or will knock over an elephant level bad small? Anyways, To use both as loaded ammunition to justify an option that a) cuts off the possibility of doing only _one_ thing b) mandates doing two steps is hilarious. In a Kafkaesque, my god, I'm a giant beetle everything still sucks kind of way. #wat - @domenic 2. All the standard combinators call .then not .chain. c) This isn't a reason against including .chain. d) .chain has one reasonably well known standard combinator on top of it: .then. e) Other less standard combinators will compose .chain, perhaps in ES.next. .chain'ists don't care about higher levels. They want someone to not wall off the damned ground floor entrance. Compose away, put whatever higher order stuff you want in, awesome, users will love it. But leave a non-composed primitive underneath, please, something that JUST does one thing: signals listeners with a value when it's ready, whatever that value happens to be. Using yet-higher order combinators to debase no-composition is #2. 3. Including .chain requires always-wrapping resolve, observability trumps optimizability. What does this effect beyond .resolve()? How much .resolve is out in the world? I'd love more on this. What I've got is from the meeting notes: A resolve of a resolve does not create multiple levels of wrapping. Without chain this is not observable. -MM .chain() requires over-wrapping/-unwrapping, without chain this is unobservable and therefore optimizable -- says to reject chain -be What use cases are being debated here? I haven't seen STH or LH's proposals for chain/compromise, they are just short sentance fragments in the notes. It's hard to get a grasp on the magnitude/maturity of the optimization being discusssed here, this final point that swayed BE and YK. There's really a 0 implicit in this: 0. Monadic vs. non-monadic is an exclusive or -- you can't have it all. #3 is the only point I concede as being even possibly concrete, and is a question of optimizability, the extent of which hasn't been spoken to. The first are mere stylistic/ opinion-based assertions which cannot be contested. The compromises proposed having it all. It was literally closing minutes of ES6 when a new thing floated into sight and changed one person's mind. A second member attested that they'd rather not hold the show up, that they'd rather stamp this than old up ES6, and that all seems so ignoble, and it seems like .resolve() is such a tiny trivial barely used thing to make a you can't have it all case out of. Please help me, help others understand what #3 entails, what made it seem so so onerous. Yes, .resolve() was going to have to keep creating new wrappings: that was the point of chain! What else is there? TC39, ES6: please make the simpler uncomposed base case available. Un-finizale. Give users access to the base material. Allow people to engineer flow control: .then() insist on one brand of flow control, returns only a final done thing: please give the ability for promise chains to be used in not-yet-determined computation. MF --- Postscript: There seems to be some kind of notion floating about that hey, you can just box your promises in an object and they won't resolve. This is only true for producers. If you use any existing promises based system, you will have no way what so ever to pull a chain out of it. .chain allows consumers to decide how to consume (it's an opt in thing), boxing has to be done producer side (up- front desgin). Please please please: let a promise return something that hasn't happened yet, so that _that_ promise can be reasoned about. --- Post-post-script: Async map(/monadic) really obfuscate what's being talked about to me. I respect that people can have conversations about it, and I'm sure you can understand the score marks as you talk back and forth over them, but I think it leaves a lot of people unable to grasp the issue itself: The ability to return a value something from the the future out of a promise, versus promises never ever being able to return anything but done, here's the final thing. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
mfo...@eldergods.com wrote: #3 is the only point I concede as being even possibly concrete Then you get a *plonk*, or at least a demeric, for ignoring the very concrete problem #2: combinators such as .all do not use .chain, they use .then. Also for ignoring #1 -- it doesn't matter that .then is compound, complex, multifarious -- it's a de-facto standard. And it is what combinators (#2) in the standard use, so you can't ignore the committee bloat or unioning cost. Imagine we simplified to do just .chain and .cast, and combinators called .chain. We'd be breaking compatibility with extant promises libraries, and de-jure future-banning .then/.resolve as an API alternative. The existing promises library users would be faced with a porting problem whose size is hard to estimate, since they are relying on assimilation and unwrapping happening behind the scenes. Promises *happened*. They are real. That's why I tweeted about #realism. Wanting something value-ish, featureless, monadic, is a good goal for a differently named abstraction built on value objects. Promises are not that abstraction. Do the work to show the win, under a new name (Future?). Until then this is selective arguing and cheap talk. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Brendan Eich mailto:bren...@mozilla.com February 4, 2014 at 7:46 PM Then you get a *plonk*, or at least a demeric, demerit', of course. But I'm talking to a fake address. That's pretty bad, it makes me want to ignore you (*plonk* in USENET terms). Do better quickly, or else that's the right outcome. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Wanting something value-ish, featureless, monadic, is a good goal for a differently named abstraction built on value objects. Promises are not that abstraction. Do the work to show the win, under a new name (Future?). I believe the win has already been shown, though: Futures would of course give you the same thing Promises do while supporting those additional use cases where you don't want recursive unwrapping. My concern is settling on a shortsighted implementation that artificially limits use cases. #2: combinators such as .all do not use .chain, they use .then Is this such a big deal? If you have .chain then you have .then, so you can certainly have it all. Imagine we simplified to do just .chain and .cast, and combinators called .chain. We'd be breaking compatibility with extant promises libraries IMO, leave .all and the rest of the combinators as they are using .then. I would not mind so long as .chain is intact. --Mark On Tue, Feb 4, 2014 at 7:48 PM, Brendan Eich bren...@mozilla.com wrote: Brendan Eich mailto:bren...@mozilla.com February 4, 2014 at 7:46 PM Then you get a *plonk*, or at least a demeric, demerit', of course. But I'm talking to a fake address. That's pretty bad, it makes me want to ignore you (*plonk* in USENET terms). Do better quickly, or else that's the right outcome. /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 like your looking forwards to the future Future, but I really want to understand the conflict underneath Promises. I'm not trying to selectively pick issues out, I'm trying to get a general sense for where the conflict lies that kicked .chain out from complemeting the spec. The existing promises library users would be faced with a porting problem whose size is hard to estimate Naive go here; Promise.prototype.then= function(fn){ function recurse(val){ if(val.chain) val.chain(recurse) else fn(val) } return this.chain(recurse) } combinators such as .all do not use .chain, they use .then. I've argued for nothing but giving everyone as many combinators as they want in the spec. .then is a combinator of .chain, .all .some combinators of .then: fine, great, shiny. You all get to join the spec, we won't try to change you into doing something other than what you do now. Embrace the de riguere standards! These are not any reason the existing combinators cannot specify an underpinning .chain that doesn't auto-unwrap. De jure has the chance to rule that we can have it all, and the naive silly cheap code above moves towards that promise, starts to show that the two are one the same, it's just a question of what is pinned underneath. I tend to believe there is for sure something real, and interesting under #3: that there was a real issue in implementation that drove ES6 at the very last hour away from .chain serving as the basis for .then. If you want something other than cheap words an unreality, perhaps you'd color in some of those details. MF On Tue, Feb 04, 2014 at 07:46:36PM -0800, Brendan Eich wrote: mfo...@eldergods.com wrote: #3 is the only point I concede as being even possibly concrete Then you get a *plonk*, or at least a demeric, for ignoring the very concrete problem #2: combinators such as .all do not use .chain, they use .then. Also for ignoring #1 -- it doesn't matter that .then is compound, complex, multifarious -- it's a de-facto standard. And it is what combinators (#2) in the standard use, so you can't ignore the committee bloat or unioning cost. Imagine we simplified to do just .chain and .cast, and combinators called .chain. We'd be breaking compatibility with extant promises libraries, and de-jure future-banning .then/.resolve as an API alternative. The existing promises library users would be faced with a porting problem whose size is hard to estimate, since they are relying on assimilation and unwrapping happening behind the scenes. Promises *happened*. They are real. That's why I tweeted about #realism. Wanting something value-ish, featureless, monadic, is a good goal for a differently named abstraction built on value objects. Promises are not that abstraction. Do the work to show the win, under a new name (Future?). Until then this is selective arguing and cheap talk. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Mark Roberts wrote: Wanting something value-ish, featureless, monadic, is a good goal for a differently named abstraction built on value objects. Promises are not that abstraction. Do the work to show the win, under a new name (Future?). I believe the win has already been shown, though: Futures would of course give you the same thing Promises do while supporting those additional use cases where you don't want recursive unwrapping. No. Future as a featureless value object would not have any of the identity-based problems reference types including Promises have. It would become its result when fulfilled. You would not be able to do much with a Future other than then it. There would be no thenable assimilation via duck-typing of thenables. #2: combinators such as .all do not use .chain, they use .then Is this such a big deal? If you have .chain then you have .then, so you can certainly have it all. That .then would be based on .chain is irrelevant. Anyone using .all would not get .chain and would potentially depend on all the .then magic. Purists trying to use only .chain would need to write their own .chainAll, etc., which would not be in the standard. Imagine we simplified to do just .chain and .cast, and combinators called .chain. We'd be breaking compatibility with extant promises libraries IMO, leave .all and the rest of the combinators as they are using .then. I would not mind so long as .chain is intact. See above. This does not wash unless you aren't using combinators at all, or you are rolling your own -- in which case we have a bloated do both forked standard. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
mfo...@eldergods.com wrote: The existing promises library users would be faced with a porting problem whose size is hard to estimate Naive go here; Promise.prototype.then= function(fn){ function recurse(val){ if(val.chain) val.chain(recurse) else fn(val) } return this.chain(recurse) } That's not how .then works in any existing library I know of. It's not how .then works in Promises/A+ (http://promises-aplus.github.io/promises-spec/). That is not going to interop with anything thenable. It introduces a new chainable (duck-typed, no function value test even, .chain truthy property). There is no point in showing a trivial but incompatible layering of .then on .chain. That's not the issue. Here is V8's .chain-based, self-hosted-in-V8's-JS-for-builtins-dialect, Promise.prototype.then implementation: function PromiseThen(onResolve, onReject) { onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; var that = this; var constructor = this.constructor; return this.chain( function(x) { x = PromiseCoerce(constructor, x); return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); }, onReject ); } Notice the recursion is not via .chain, rather (and only if IsPromise(x), a nominal type test) via .then. I tend to believe there is for sure something real, and interesting under #3: that there was a real issue in implementation that drove ES6 at the very last hour away from .chain serving as the basis for .then. If you want something other than cheap words an unreality, (I have no idea what cheap words an unreality means here. Should I care?) perhaps you'd color in some of those details. It's pretty simple. Adding .chain in addition to library-compatible .then means Promise.resolve must always make a new promise, even for a promise argument. Otherwise you can't compose resolve and chain to wrap once always and unwrap once only, respectively. Drop .chain, use only .then, and resolve can cast instead of wrap, which some promises libraries that lack chain indeed do today (an optimization, #3 in your cited text, my point (3)). Having the two APIs together require what V8's self-hosted, .chain-extended implementation does: always wrapping the argument x to Promise.resolve in a new Promise. That's the problem I numbered (3). Clear? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
I do believe it meant to say 'cheap words and unreality'. Nothing to care about. On Tue, Feb 4, 2014 at 11:04 PM, Brendan Eich bren...@mozilla.com wrote: mfo...@eldergods.com wrote: The existing promises library users would be faced with a porting problem whose size is hard to estimate Naive go here; Promise.prototype.then= function(fn){ function recurse(val){ if(val.chain) val.chain(recurse) else fn(val) } return this.chain(recurse) } That's not how .then works in any existing library I know of. It's not how .then works in Promises/A+ (http://promises-aplus.github.io/promises-spec/). That is not going to interop with anything thenable. It introduces a new chainable (duck-typed, no function value test even, .chain truthy property). There is no point in showing a trivial but incompatible layering of .then on .chain. That's not the issue. Here is V8's .chain-based, self-hosted-in-V8's-JS-for-builtins-dialect, Promise.prototype.then implementation: function PromiseThen(onResolve, onReject) { onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; var that = this; var constructor = this.constructor; return this.chain( function(x) { x = PromiseCoerce(constructor, x); return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); }, onReject ); } Notice the recursion is not via .chain, rather (and only if IsPromise(x), a nominal type test) via .then. I tend to believe there is for sure something real, and interesting under #3: that there was a real issue in implementation that drove ES6 at the very last hour away from .chain serving as the basis for .then. If you want something other than cheap words an unreality, (I have no idea what cheap words an unreality means here. Should I care?) perhaps you'd color in some of those details. It's pretty simple. Adding .chain in addition to library-compatible .then means Promise.resolve must always make a new promise, even for a promise argument. Otherwise you can't compose resolve and chain to wrap once always and unwrap once only, respectively. Drop .chain, use only .then, and resolve can cast instead of wrap, which some promises libraries that lack chain indeed do today (an optimization, #3 in your cited text, my point (3)). Having the two APIs together require what V8's self-hosted, .chain-extended implementation does: always wrapping the argument x to Promise.resolve in a new Promise. That's the problem I numbered (3). Clear? /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
Ryan Scheel wrote: I do believe it meant to say 'cheap words and unreality'. Nothing to care about. Thanks -- makes me not care about replying, you are right! /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 29 Jan 2014 03:42, Brendan Eich bren...@mozilla.com wrote: And so we will go with 'chain'. I assume it has been pointed out before that Underscore/LoDash have popularised their own chain function/concept? http://underscorejs.org/#chaining Hopefully it's distant enough from Promise-world to alleviate most confusion, but I thought I'd point it out for completeness. On the flatMap name, as a Scala developer, I find it quite conveniently describes the flattening nature of the operation, although it only really works thanks to the parallel with map: M[A]#map(f: A = B): M[B] M[A]#flatMap(f: A = M[B]): M[B] (not M[M[B]] as it would with map - hence the flat) But given that 'then' is a sort of a mix of map/flatMap (and flatThen is terrible), I don't think there is an obvious parallel currently. Seeing as flatMap/chain is being discussed though, have there been plans to add a map method on Promises (that would map to a new Promise without unwrapping returned promises)? And have there been any discussion to add other monadic types to ES, eg Option/Maybe, Try, etc, or to make existing types support more monadic operations, eg Array.prototype.flatMap (or chain?). Thanks, and sorry if this has been discussed before (is there any way to catch up on such topics if it has, short of reading piles of minutes?). On 29 January 2014 03:42, Brendan Eich bren...@mozilla.com wrote: Quildreen Motta wrote: I suppose using names that don't give you a hint of the meaning of the operation fits perfectly Haskell's (and Scalaz's) Avoid Success At All Costs tradition lulz. And so we will go with 'chain'. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Sébastien Cevey Software Developer Please consider the environment before printing this email. -- Visit theguardian.com On your mobile, download the Guardian iPhone app theguardian.com/iphone and our iPad edition theguardian.com/iPad Save up to 57% by subscribing to the Guardian and Observer - choose the papers you want and get full digital access. Visit subscribe.theguardian.com This e-mail and all attachments are confidential and may also be privileged. If you are not the named recipient, please notify the sender and delete the e-mail and all attachments immediately. Do not disclose the contents to another person. You may not use the information for any purpose, or store, or copy, it in any way. Guardian News Media Limited is not liable for any computer viruses or other material transmitted with or as part of this e-mail. You should employ virus checking software. Guardian News Media Limited A member of Guardian Media Group plc Registered Office PO Box 68164 Kings Place 90 York Way London N1P 2AP Registered in England Number 908396 -- ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
While the getMyPromise question wasn't answered yet and still isn't clear to me, from the other posts I think it can be reworded this way: ```js var p1 = Promise.resolve(Promise.cast(1)); var p2 = Promise.cast(Promise.cast(1)); ``` p1 and p2 will have a different internal state, but there is no way to tell the difference between the two (and no way to write a regression test to check that the internal state is correct), until in the future a new method will be defined. Is this correct? What about the case of: ```js var p3 = new Promise(resolve = resolve(Promise.cast(1)); ``` Will the state of p3 be more similar to that of p1 or that of p2? I'll file a bug when I understand the situation better. Regards, Paolo On 28/01/2014 21.07, Paolo Amadini wrote: I don't have a background on the .flatMap level of abstraction. In the following scenario, will users of getMyPromise() have a different behavior with .flatMap if the library code used cast rather than resolve? If so, this can definitely lead to confusion when .flatMap is introduced in the future since the callers cannot be sure about what the library did internally, assuming the library authors didn't intentionally choose one or the other. ```js // -- MyLibrary.js function getMyPromise() { var a = condition ? getMyOtherPromise() : value2; return Promise.resolve(a); } function getMyOtherPromise() { return Promise.resolve(value1); } ``` ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 29/01/2014 5.12, Kris Kowal wrote: In this case, a half pursuit of type purity is a side quest at the expense of users. Having two ways to resolve and two ways to observe a promise is unnecessarily confusing. In my experience, one method like then, that unwraps recursively, and one function, like Promise.cast, that automatically lifts if necessary, and then handlers that return into the waiting hands of Promise.cast are coherent and ergonomic. Having a choice between cast and resolve and a choice between then and chain, will leave developers unnecessarily confused and worried all the while they use or abandon Promises as too subtle. As an imperative programmer, I confirm I'm left worried and confused ;-) But I understand that functional programming might need more complexity. I would be less confused if functionality that is only relevant for functional programming would be separate and inaccessible by default, even if supported and optimized at the implementation level. For example: ```js let p1 = FunctionalPromise.accept(...) FunctionalPromise.chain(p1, ...) ``` And no Promise.accept or p1.chain methods to be chosen over Promise.cast and p1.then. Paolo ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 29 January 2014 10:45, Paolo Amadini paolo.02@amadzone.org wrote: On 29/01/2014 5.12, Kris Kowal wrote: In this case, a half pursuit of type purity is a side quest at the expense of users. Having two ways to resolve and two ways to observe a promise is unnecessarily confusing. In my experience, one method like then, that unwraps recursively, and one function, like Promise.cast, that automatically lifts if necessary, and then handlers that return into the waiting hands of Promise.cast are coherent and ergonomic. Having a choice between cast and resolve and a choice between then and chain, will leave developers unnecessarily confused and worried all the while they use or abandon Promises as too subtle. As an imperative programmer, I confirm I'm left worried and confused ;-) But I understand that functional programming might need more complexity. It is, actually, more simplicity. The concept of `Promise.resolve` and `Promise.chain` is simpler than `Promise.cast` and `Promise.then` (i.e.: they represent orthogonal concepts, not complected). `Promise.cast` and `Promise.then` may be, arguably, *easier* to work with, from a user POV, since you don't need to make as many choices. I would argue that it would make more sense to write `cast` and `then` in terms of `resolve` and `chain`, however. But this seems to have already been decided. Answering your previous question: ```js var p1 = Promise.resolve(Promise.cast(1)); var p2 = Promise.cast(Promise.cast(1)); ``` `p1` will be a `Promise(Promise(1))`, whereas `p2` will be `Promise(1)` — IOW, `Promise.resolve` will just put anything inside of a `Promise`, regardless of that being a promise or a regular value, whereas `Promise.cast` will put the innermost value that is not a promise inside of a promise. ```js var p3 = new Promise(resolve = resolve(Promise.cast(1)); // is the same as: var p3 = Promise.resolve(Promise.cast(1)) ``` -- -- Quildreen (Soreλ\a) Motta (http://robotlolita.github.io/http://killdream.github.com/ ) *— JavaScript Alchemist / Minimalist Designer / PLT hobbyist —* ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
It is, actually, more simplicity. The concept of `Promise.resolve` and `Promise.chain` is simpler than `Promise.cast` and `Promise.then` (i.e.: they represent orthogonal concepts, not complected). `Promise.cast` and `Promise.then` may be, arguably, *easier* to work with, from a user POV, since you don't need to make as many choices. I would argue that it would make more sense to write `cast` and `then` in terms of `resolve` and `chain`, however. But this seems to have already been decided. It does make more sense, and from my point of view it's not decided. What is decided is the AP2 design. That is: 1) promises are fully parametric and, 2) `then` recursively unwraps the *input* to its callbacks. For the sake of coherency (aka conceptual integrity), `then` needs to be written in terms of `chain`. This issue needs to be resolved ASAP, however, since promises are making their way into engines now. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
My take is that the difference between cast and resolve is so subtle that I don't think it captures developer intention. In other words, if I see some code calling Promise.cast(otherPromise), I can't be sure that the developer made an intentional choice over Promise.resolve(otherPromise). Note that `Promise.resolve(p)`, where p is a promise, does *not* return an eventual for the eventual value of p. Rather, it returns an eventual for p, literally. Promises should be considered fully parametric (in other words, nestable). If you want to convert a maybe-promise into a promise, then you want `cast`. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On Tuesday, January 28, 2014 10:13 AM, Kevin Smith zenpars...@gmail.com wrote: My take is that the difference between cast and resolve is so subtle that I don't think it captures developer intention. In other words, if I see some code calling Promise.cast(otherPromise), I can't be sure that the developer made an intentional choice over Promise.resolve(otherPromise). Note that `Promise.resolve(p)`, where p is a promise, does *not* return an eventual for the eventual value of p. Rather, it returns an eventual for p, literally. Promises should be considered fully parametric (in other words, nestable). That's not true as per the last consensus. There was `Promise.fulfill(p)` which would've nested promises, but it was left for ES7 to investigate fulfill+flatMap. Juan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
That's not true as per the last consensus. There was `Promise.fulfill(p)` which would've nested promises, but it was left for ES7 to investigate fulfill+flatMap. I don't think that statement is correct. Domenic, Allen, Mark, can we get a ruling? : ) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
I am hesitant to retread, but I suppose we should clear up the confusion of the last few messages. Indeed, things evolved slightly since the last consensus, to the point where the solution that made the most sense was to store the promise's resolution value (whatever it may be) then do the unwrapping entirely inside `then`. So effectively, `Promise.resolve` is now what `Promise.fulfill` used to be; however, because `then` unwraps, in practice `then` users will not notice a difference (i.e. promises for promises are not observable). ES7-timeframe monad additions to the standard library could indeed make use of the stored resolution value. To bring things down to earth more: The following code will retain GC references to all of the variables, including `p2`, `p3`, and `p4`: ```js var p1 = Promise.cast(1); var p2 = Promise.resolve(gcRoot.p1); var p3 = Promise.resolve(p2); gcRoot.p4 = Promise.resolve(p3); ``` `gcRoot.p4` maintains a reference to `p3`, which maintains a reference to `p2`, which maintains a reference to `p1`. Whereas, given ```js var p1 = Promise.cast(1); var p2 = Promise.cast(gcRoot.p1); var p3 = Promise.cast(p2); gcRoot.p4 = Promise.cast(p3); ``` we have that all the variables are equal, i.e. `p1 === p2`, `p2 === p3`, and `p3 === gcRoot.p4`. --- With all that said, I somewhat agree with the sentiment of the OP that `Promise.resolve` is pointless, and even (from a memory consumption POV), a footgun. However, we settled on keeping it, based on a few weak arguments: - Symmetry with `Promise.reject(r)` ≈ `new Promise((resolve, reject) = reject(r))`; we should also have `Promise.resolve(x)` ≈ `new Promise((resolve, reject) = resolve(x))`. - Sometimes you want to guarantee object non-identity so a shorthand is useful (Tab Atkins had some use case involving CSS specs). You can peruse the issue tracker for more discussion. We're certainly retreading old ground here. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
First, q = Promise.fulfill(p) never made any sense, as if p is pending, then q cannot be fulfilled -- there's no non-promise value to fulfill it to. Remember, a promise is fulfilled when it's (original) .then would invoke its first (onFulfilled) callback. fulfilled, rejected, pending are at the .then level of abstraction. At the .flatMap level of abstraction, the fulfill-like concept is accept. Promise q accepts value (whether promise or non-promise) v when q's (original) .flatMap would invoke its first (onAccept) callback. accept is fully parametric, at the .flatMap level of abstraction, where fully parametric is meaningful. So, except for the name of the old operation we're no longer using, I agree with Domenic. It is not that we renamed Promise.fulfill to Promise.resolve, we killed Promise.fulfill because it was incoherent, and we renamed Promise.accept to Promise.resolve. For people concerned only about the .then level of abstraction, I see little reason to ever use Promise.resolve rather than Promise.cast, and much reason to prefer Promise.cast. But fwiw we did agree to express the difference now, to be perceived by future and experimental uses of .flatMap in the future. On Tue, Jan 28, 2014 at 10:20 AM, Juan Ignacio Dopazo jdop...@yahoo-inc.com wrote: On Tuesday, January 28, 2014 10:13 AM, Kevin Smith zenpars...@gmail.com wrote: My take is that the difference between cast and resolve is so subtle that I don't think it captures developer intention. In other words, if I see some code calling Promise.cast(otherPromise), I can't be sure that the developer made an intentional choice over Promise.resolve(otherPromise). Note that `Promise.resolve(p)`, where p is a promise, does *not* return an eventual for the eventual value of p. Rather, it returns an eventual for p, literally. Promises should be considered fully parametric (in other words, nestable). That's not true as per the last consensus. There was `Promise.fulfill(p)` which would've nested promises, but it was left for ES7 to investigate fulfill+flatMap. Juan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
[Replying here since I'm not sure about how to move the discussion to the issue tracker without losing the context of Mark's observation.] On 28/01/2014 20.28, Mark S. Miller wrote: For people concerned only about the .then level of abstraction, I see little reason to ever use Promise.resolve rather than Promise.cast, and much reason to prefer Promise.cast. But fwiw we did agree to express the difference now, to be perceived by future and experimental uses of .flatMap in the future. I don't have a background on the .flatMap level of abstraction. In the following scenario, will users of getMyPromise() have a different behavior with .flatMap if the library code used cast rather than resolve? If so, this can definitely lead to confusion when .flatMap is introduced in the future since the callers cannot be sure about what the library did internally, assuming the library authors didn't intentionally choose one or the other. ```js // -- MyLibrary.js function getMyPromise() { var a = condition ? getMyOtherPromise() : value2; return Promise.resolve(a); } function getMyOtherPromise() { return Promise.resolve(value1); } ``` ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
So, if I understand correctly, it basically boils down to: Promise.resolve :: a → Promise(a) Promise.cast :: a → Promise(a) Promise.cast :: Promise(a) → Promise(a) But right now we'll only get `.then`, so transformations with nested promises will flatMap automatically: Promise.then :: (Promise(a)) = ((a → MaybePromise(b), (a → MaybePromise(b)) Promise.then :: (Promise(Promise(a))) = ((a → MaybePromise(b), (a → MaybePromise(b)) But later, once `flatMap` is introduced, you'll be able to deal with nested promises without breaking parametricity: Promise.flatMap :: (Promise(a)) = (a → Promise(b)) If that's correct, I don't see any use cases for Promise.resolve right now, unless a library where to provide a corresponding unspecified `flatMap` implementation. On 28 January 2014 18:07, Paolo Amadini paolo.02@amadzone.org wrote: [Replying here since I'm not sure about how to move the discussion to the issue tracker without losing the context of Mark's observation.] On 28/01/2014 20.28, Mark S. Miller wrote: For people concerned only about the .then level of abstraction, I see little reason to ever use Promise.resolve rather than Promise.cast, and much reason to prefer Promise.cast. But fwiw we did agree to express the difference now, to be perceived by future and experimental uses of .flatMap in the future. I don't have a background on the .flatMap level of abstraction. In the following scenario, will users of getMyPromise() have a different behavior with .flatMap if the library code used cast rather than resolve? If so, this can definitely lead to confusion when .flatMap is introduced in the future since the callers cannot be sure about what the library did internally, assuming the library authors didn't intentionally choose one or the other. ```js // -- MyLibrary.js function getMyPromise() { var a = condition ? getMyOtherPromise() : value2; return Promise.resolve(a); } function getMyOtherPromise() { return Promise.resolve(value1); } ``` ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- -- Quildreen (Soreλ\a) Motta (http://robotlolita.github.io/http://killdream.github.com/ ) *— JavaScript Alchemist / Minimalist Designer / PLT hobbyist —* ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Quildreen Motta wrote: If that's correct, I don't see any use cases for Promise.resolve right now, unless a library where to provide a corresponding unspecified `flatMap` implementation. IIRC (and I may not; endless promises threads make me sleepy) this is the reason to have Promise.resolve: to enable some to blaze the flatMap trail ahead of ES6. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Promise.cast and Promise.resolve
From: es-discuss es-discuss-boun...@mozilla.org on behalf of Brendan Eich bren...@mozilla.com Quildreen Motta wrote: If that's correct, I don't see any use cases for Promise.resolve right now, unless a library where to provide a corresponding unspecified `flatMap` implementation. IIRC (and I may not; endless promises threads make me sleepy) this is the reason to have Promise.resolve: to enable some to blaze the flatMap trail ahead of ES6. Kind of. Since `Promise.resolve(x)` is just `new Promise(resolve = resolve(x))`, the only reasons for including that shorthand method are symmetry and the idea that this operation might be common enough to necessitate a shorthand. See my earlier reply. On the other hand, that *is* part of the reason we moved all the unwrapping to the `then` side---as Mark puts it, using the accept operation instead of resolve, albeit while still using the resolve name. (Which is pretty confusing when you try to explain it, but I swear, it makes sense...) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
Domenic Denicola wrote: From: es-discusses-discuss-boun...@mozilla.org on behalf of Brendan Eichbren...@mozilla.com Quildreen Motta wrote: If that's correct, I don't see any use cases for Promise.resolve right now, unless a library where to provide a corresponding unspecified `flatMap` implementation. IIRC (and I may not; endless promises threads make me sleepy) this is the reason to have Promise.resolve: to enable some to blaze the flatMap trail ahead of ES6. Kind of. Since `Promise.resolve(x)` is just `new Promise(resolve = resolve(x))`, the only reasons for including that shorthand method are symmetry and the idea that this operation might be common enough to necessitate a shorthand. See my earlier reply. On the other hand, that*is* part of the reason we moved all the unwrapping to the `then` side---as Mark puts it, using the accept operation instead of resolve, albeit while still using the resolve name. (Which is pretty confusing when you try to explain it, but I swear, it makes sense...) I buy it. Paolo may not. Mozilla XUL JS does seem full of .resolve calls, some of which might want to be .cast calls instead. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Promise.cast and Promise.resolve
On 28 January 2014 21:21, Quildreen Motta quildr...@gmail.com wrote: So, if I understand correctly, it basically boils down to: Promise.resolve :: a → Promise(a) Promise.cast :: a → Promise(a) Promise.cast :: Promise(a) → Promise(a) But right now we'll only get `.then`, so transformations with nested promises will flatMap automatically: Promise.then :: (Promise(a)) = ((a → MaybePromise(b), (a → MaybePromise(b)) Promise.then :: (Promise(Promise(a))) = ((a → MaybePromise(b), (a → MaybePromise(b)) This type is not really accurate. Due to recursive unwrapping, `then' has no type you could express in any reasonable type system -- the argument type can be an arbitrary tower of nested promises (and the maximum one for each use). As you note below, this makes the operation inherently non-parametric. (Which is why I still hold up that recursive unwrapping is a bad idea, especially as the core primitive.) But later, once `flatMap` is introduced, you'll be able to deal with nested promises without breaking parametricity: Promise.flatMap :: (Promise(a)) = (a → Promise(b)) If that's correct, I don't see any use cases for Promise.resolve right now, unless a library where to provide a corresponding unspecified `flatMap` implementation. The V8 implementation provides it under the name `chain', with the obvious semantics. /Andreas On 28 January 2014 18:07, Paolo Amadini paolo.02@amadzone.org wrote: [Replying here since I'm not sure about how to move the discussion to the issue tracker without losing the context of Mark's observation.] On 28/01/2014 20.28, Mark S. Miller wrote: For people concerned only about the .then level of abstraction, I see little reason to ever use Promise.resolve rather than Promise.cast, and much reason to prefer Promise.cast. But fwiw we did agree to express the difference now, to be perceived by future and experimental uses of .flatMap in the future. I don't have a background on the .flatMap level of abstraction. In the following scenario, will users of getMyPromise() have a different behavior with .flatMap if the library code used cast rather than resolve? If so, this can definitely lead to confusion when .flatMap is introduced in the future since the callers cannot be sure about what the library did internally, assuming the library authors didn't intentionally choose one or the other. ```js // -- MyLibrary.js function getMyPromise() { var a = condition ? getMyOtherPromise() : value2; return Promise.resolve(a); } function getMyOtherPromise() { return Promise.resolve(value1); } ``` ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- -- Quildreen (Soreλ\a) Motta (http://robotlolita.github.io/) — JavaScript Alchemist / Minimalist Designer / PLT hobbyist — ___ 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
Andreas Rossberg wrote: `flatMap` ... The V8 implementation provides it under the name `chain', with the obvious semantics. +1 on chain as name, not flatMap, but Haskell'ers should weigh in. Wait, no. :-P /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss