<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Apr 29, 2015, at 12:40 PM, C. Scott Ananian wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Apr 29, 2015 at 3:32 PM, Allen Wirfs-Brock <span dir="ltr"><<a href="mailto:allen@wirfs-brock.com" target="_blank">allen@wirfs-brock.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><div class="h5"><div>On Apr 29, 2015, at 12:24 PM, C. Scott Ananian wrote:</div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Apr 29, 2015 at 3:09 PM, Allen Wirfs-Brock <span dir="ltr"><<a href="mailto:allen@wirfs-brock.com" target="_blank">allen@wirfs-brock.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div> class DefensivePromise extends Promise {</div>  constructor(x) {<br>    super(x);<br>    if (new.target === DefensivePromise) {<br></div></blockquote><div>           // I'm assuming this test is just to be subclass friendly and allow subclasses to freeze later? </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">      Object.freeze(this);<br><div>    }<br>  }<br>  static resolve(x) {<br>    switch (true) {</div><div>       default:</div></div></blockquote><div>         // I guess a do { } while(false); would work as well? </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>          // assuming frozen primordial</div><div>          if (x.constructor !== DefensivePromise) break;  //just a quick exit, doesn't guarantee much</div><div>          if (!Object.isFrozen(x)) break;</div><div>          If (Object.getOwnPropertyDescriptor(x, 'then')) break;</div><div>          //a more subclass friendly approach would walk x's [[Prototype]] chain to ensure that the correct 'then' is inherited from frozen prototypes</div><div>          if (Object.getPrototypeOf(x) !== DefensivePromise.prototype) break;</div><div>          //Assert: x.then === Promise.prototype.then, now and forever after</div><div>          return x;</div><div>     }</div><div>     // must be called on a subclass of DefensivePromise, so we don't need to enforce the 'then' invariant </div><div>     If  (x.constructor ===  this) return x;   //in which case a constructor check is good enough</div></div></blockquote><div>          // ^^ this is a mistake right?  I think this line doesn't belong. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>     return new this(r => {r(x)});<br>   }<br> }</div><div>Object.freeze(DefensivePromise);</div><div>Object.freeze(DefensivePromise.prototype);</div></div></blockquote></div><br></div><div class="gmail_extra">It's not clear what the `x.constructor` test is still doing in your implementation.</div></div></blockquote><div><br></div></div></div><div>Do you mean the first or second occurrence?</div></div></div></blockquote><div><br></div><div>The second occurrence.  At that point all we know about x is that it's *not* something safe.  We shouldn't be looking at `constructor` in that case.</div></div></div></div></blockquote><div><br></div><div>the last two lines of the above `resolve` method should be replaced with:</div><div>     return super.resolve(x)</div><div><br></div><div>x.construct === this is the test that I propose Promise.resolve should make instead of  testing [[PromiseConstructor]]</div><div>There should probably also be another test that SpeciesConstrutor(x)===this </div><div><br></div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><span class=""><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">But, regardless of the details of our implementations, can we agree that "tamper proof" promises don't seem to need the [[PromiseConstructor]] property?</div></div></blockquote><div><br></div></span><div>I agree with you, but I'm not the Promise champion.</div><div><br></div><div>Regardless, too late for ES2015.  It will have to proposed as an ES2016 change.</div></div></div></blockquote><div><br></div><div>True, but since subclassable Promises haven't been implemented in the major engines yet, still in time to get everyone to agree to implement the new semantics before use "in the wild" locks in the warts of ES2015.</div><div><br></div><div>If we get consensus, I can certainly ensure that es6-shim, core-js, and babel implement the "ES2016" semantics.</div></div></div></div></blockquote><div><br></div>I wouldn't jump the gun until we actually have TC39 consensus on a proposal.</div><div><br></div><div>What we've shown is that the [[PromiseConstructor]] test was never sufficient to guarantee the invariant that Mark is concerned about and also that there probably isn't a generic check we can do that would satisfy his requirements.  He has do it himself like shown above.  But the specified [[PromiseConstructor]] test doesn't  really hurt anything.  It places some slight limitations on what subclasses can do, but probably doesn't interfere with anything an actual subclass is likely to do.  It seems like a restriction than can be relaxed in the future without anybody (or than conformance tests) noticing.</div><div><br></div><div>Allen</div><div><br></div></body></html>