New ES6 draft now available

David Bruant bruant.d at gmail.com
Sun Nov 25 07:42:01 PST 2012


Le 25/11/2012 01:32, Brendan Eich a écrit :
> David Bruant wrote:
>> Here is an idea to uniformize the enumeration story while removing 
>> enumeration inconsistency footgun. I'll describe it in proxy trap 
>> terms. A unique trap (or internal operation)
>> keyEnumerate: () -> iterator for {propertyKey, enumerable}
>> There is this unique operation which returns an iterator not for 
>> property keys, but for an object containing a property key and a 
>> boolean signifying the enumerable boolean.
>> Using this, each userland operation would use this iterator, drain it 
>> out (unless the iteration is being aborted like by throwing in a 
>> for-in loop) and filter out based on the exact userland operation so 
>> that:
>> * All would filter out if propertyKey is ever a private symbol
>> * Object.getOwnPropertyNames would keep all other property keys 
>> regardless of the enumerable value
>> * Object.keys would filter out properties which are described as 
>> non-enumerable
>> * for-in would filter out non-enumerable and retrieve the different 
>> keyEnumerate from the prototype chain objects.
>> With this unique internal operation, an object is able to communicate 
>> its intent regarding what's enumerated and each enumeration userland 
>> operation only keeps what it's interested in.
>
> As an internal method architecture for the spec, this seems fine -- 
> the "object" returned cannot be observed and could be an internal 
> type, a la Reference.
>
> For a proxy trap (...)
I think the trap and the internal operations should work the same (same 
signature) in order to be used interchangebly by userland operations.

> (...) this seems too low-level and the overhead (without optimization 
> to look into the continuation for a destructuring pattern and avoid 
> the object allocation) is again a potential problem. Tom should weigh in.
Even in cases where the allocation can't be optimized, in practice, 
these objects will be very short-lived, so generational GC will do their 
work. If handler authors make these object long-lived or anything 
weird/complicated, I think it's fair that they pay the price for doing so.

I'm a bit surprised by your current worry about allocations.
I had equivalent worries until a discussion with Allen about memory 
allocation [1] (was it really a year ago? Feels like yesterday to me) 
convinced me that the technology to make allocation cheap enough exists. 
After that I stopped worrying so much.
Also, the July 2012 meeting had one thing agreed upon that contained an 
equivalent object-as-output pattern (what it looked like after the July 
2012 meeting [2] and related discussion [3]). It was somehow equivalent 
design and didn't raise issues about memory allocation at the time IIRC.

On a last note with debatable (but potentially high) importance, I don't 
recall a case where I needed to implement the enumeration trap. If no 
enumeration-related trap is implemented, the operation can be forwarded 
to the target at no or epsilon cost.
Proxies which handler just forward to the target won't have a big 
overhead. Generic membranes may have an overhead, but slightly-smarter 
membranes can special-case the output of the keyEnumerate trap (this 
output will only be consumed by the engine, so no need to wrap it).
In the end, I don't know if the key enumeration trap will be usefully 
overridden in ways that can't be optimized often enough (even with 
generational GC!) to really worry about this case too much.



>> There might be an associated security worry here if any object can 
>> have its @@hasInstance changed, but one good thing is that the debate 
>> of trapping instanceof ends if it's a symbol-keyed method.
>
> Proxies have trap integrity, that is, you can't mess with their 
> handlers to mutate traps unless you are granted the handler 
> capability. Right?
I was worried about @@hasInstance to be overriden on any object, not 
just proxies.
For sure, you need the @@hasInstance private symbol capability to be 
able to change it, but people writing ES5 code with ES5 assumptions in 
mind expect instanceof to be a very stable operator. The ability to 
change it through a symbol value challenged that assumption.
Unless for all current objects @@hasInstance is a frozen property in 
which case making it a private name isn't any useful; it can just keep 
being an internal property that other specs can decide to override.

>
>>> • Defined all of the functions in the @Reflect module corresponding 
>>> to MOP internal operations.
>> IIRC __proto__ has been agreed to be an data property
>
> The jury is still out (could be accessor with poisoned reflection), 
> but this is not material to your point.
I assumed "accessor" implied "useful extractable setter" and a useful 
extractable setter has exactly the same issues than 
Reflect.setPrototypeOf. As you mentioned, the idea of an 
*.setPrototypeOf (including a useful __proto__ setter) had been covered 
a lot in the list, so I was reusing this material for my point. I had 
forgotten about the idea of a poisoned setter.

By the way, what would a poisoned setter look like?

     var o = {};
     o.__proto__ = {};
     Object.getOwnPropertyDescriptor(Object.prototype, 
'__proto__').set.call(o, {});

If the second line doesn't work as the first one does, I don't really 
see the point of reflecting as an accessor. A data property is a lie, 
but "Object.getOwnPropertyDescriptor(Object.prototype, 
'__proto__').set.call" not working as expected isn't any better IMHO.
If the extracted setter doesn't work, __proto__ might as well be a data 
property.

David

[1] https://mail.mozilla.org/pipermail/es-discuss/2011-November/018792.html
[2] https://gist.github.com/3232772#file_current_proposal.js
[3] https://mail.mozilla.org/pipermail/es-discuss/2012-August/024309.html


More information about the es-discuss mailing list