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
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to