On Apr 27, 2015, at 8:01 PM, Kevin Smith wrote:

> x = Reflect.construct(Promise, x, C);
> 
> is another fine way to fool someone who wrote "C.resolve(x)" and expected to 
> get an instance of C back.
> 
> Thanks for pointing this out.  I believe the ability to use an arbitrary 
> newTarget parameter for Reflect.construct is breaking the intent of 
> Promise.resolve.  Using an arbitrary "newTarget" is also problematic for the 
> private fields proposal.
> 
> It seems to me that Reflect.construct has been given a capability that is not 
> otherwise expressible with ES6 syntax, and that gap is problematic.
> 
> Maybe I've missed some context though.  Mark, Allen, any thoughts?

Note that the exact same kind of circumvention could have been accomplished  
with the Promise design prior to instantiation reform adding the 3rd argument 
to Construct:

x = C[Symbol.create]().apply(Promise, x);   

As to "breaking the intent of Promise.resolve", we have to look closely at what 
that intent actually is and whether "intent" is equivalent to "guarantee".   
Apparently the intent of Foo.resolve is to coerce the argument value to a the 
same type of promise object as produced by the Foo constructor (assuming that 
Foo is a constructor that inherits from Promise).  But "same type" is a very 
elusive concept of in JS.  Is an object that is initially instantiated by Foo 
still of the "same type" as other objects created by Foo if it has been mutated 
that such that it no longer has Foo.prototype on its prototype chain and/or 
shares no properties in common with the other objects created using Foo.  If an 
object created by Foo still the "same type" if additional properties are added 
to it. What if addiotnal properties are added via subclassing.  Why is an 
instance of a subclass of Foo the "same type" as an instance of Foo.  If not, 
why not?  Finally, note Foo.resolve may or may not be the same method as 
Promise.resolve, so whatever definition of "same type" that is used by 
Promise.resolve is not necessarily the definition used by Foo.resolve.

So, ES6 Promises reflect a specific set of design decisions, including a 
specific definition of "same type" that appears to exist solely for use by 
Promise.resolve.  All that design guarantees is that the object has an certain 
specific internal slot whose value is tested in a specific way by 
Promise.resolve.  It doesn't guarantee that the object is a well-promise or 
that it has any specific other characteristics that are expected of Foo 
objects. It's hard to extrapolate from that  specific design to the underlying 
intent of the designer.

This is the nature of JS objects.  There are very few guarantees about 
anything.  If you want guarantees you need to lock things down and probably add 
code to test for the guaranteed conditions.  If you want guarantees, you 
probably aren't going to use polymeric then-ables or any other form of OO 
polymorphism.   but, it's the developers choice.

> 
> Looking over the Reflect namespace, I also see that Reflect.get and 
> Reflect.set have been given powers not expressible with syntax:  the receiver 
> does not have to be a prototype parent of the target.
> 

The Receiver argument to these Reflect.get/set/construct is necessary for many 
Proxy handler use cases.

These are simply a reification of the ES MOP api and an important use case of 
them is to define exotic objects whose behaviors differ from what can be 
directly expressed using ES language level syntax. 

It's a trade-up, if you want to allow ES programmer to express things beyond 
that the syntactic language supports you can't limit that expression to what 
the syntax allows.

Allen


_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to