(Changing Subject to better identify  what is probably an important topic.)

On Nov 24, 2012, at 5:31 AM, David Bruant wrote:

> Hi,
> 
> I haven't been following very closely some of the most recent discussions, so 
> I appologize if my comments have been addressed already

(The  "possible excessive proxy invariants..."  thread 
https://mail.mozilla.org/pipermail/es-discuss/2012-November/026510.html and a 
few others are quite relevant to some of the points you raise below)

Before I plunge in, I want to provide a little back ground for lurkers.

In the Rev 12 ES6 draft, section 8.1.6 and its subsections define what I 
consider to be the ES Meta-Object Protocol (MOP).  I don't actually use that 
terminology in the specification, but it is a convenient and  concise term for 
something important so I'm going to use it below and probably in other 
discussions.

The MOP generically defines the capabilities of all objects. The MOP is the 
abstraction layer that generic language features  see and use interact with 
generic objects. If a (generic) capability is not exposed via the MOP is isn't 
available for use in specifying language features that apply to all kinds of 
objects.  There may be many different forms of objects that provide alternative 
implementations of the MOP interface.  These alternative forms include ordinary 
objects and various specified exotic objects including Proxy objects, Symbol 
objects, Array objects, etc. Other alternative forms includes what was formerly 
called "host objects" and encompasses the object forms specified by W3C's 
WebIDL. The MOP is the semantic extension point for plugging new forms of 
objects into ECMAScript.

There could be many alternative MOP designs, and the current design is highly 
derived form the legacy ES<=5.1 internal method model.  There are various 
principles that might be applied to MOP design.  Two principles I believe in 
are: 1)  The MOP should be as narrow as possible (minimize number of MOP 
methods), and 2) Don't replicate common functionality across multiple MOP 
methods.   The current ES6 draft MOP makes compromises on these principles.  I 
think we can get closer it closer to them. 

> 
> Le 23/11/2012 18:48, Allen Wirfs-Brock a écrit :
>> Changes include:
>> 
>>  • Reorganized Chapter 8 into separate language type and specification type 
>> sub sections
>>  • Added Symbol property keys to the definition of the Object Type. 
>> terminology migration from talking about “property names” to “property keys”.
> I support this change. It's somewhat minor, but clearly indicates that a 
> shift has occured.
> 
>>  • MOP changes: Added [[GetInheritance]]/[[SetInheritance]] as internal 
>> methods for accessing [[Prototype]] internal prototype chain.
> Why not [[GetPrototype]] and [[SetPrototype]]? We have a absurd number of 
> excellent resources (including but not limited to Dmitry Soshnikov and Axel 
> Rauschmayer's websites/blogs) which use extensively the ES5 internal 
> [[Prototype]]. It's also been very hard to get people to understand the 
> difference between .prototype and [[Prototype]]. I'm afraid a new change 
> would create a lot of confusion.

[[Prototype]] is now specified as internal state of ordinary objects and only 
some kinds of exotic objects. (For example, symbols and Proxy objects don't 
have that internal state).   At the MOP level [[GetP]], [[SetP]] and 
[[Enumerate]] are the only methods whose ordinary implementations cares about 
"inheritance".  There really isn't anything in the MOP that mandates prototypal 
inheritance or even single inheritance.  The MOP is currently rich enough that 
it is even possible to define object forms that support various styles of 
multiple inheritance.

However, we do have legacy language and library operations for setting 
(__proto__) and retrieving [[Prototype]]. To define those language features 
they need to show up generically in the MOP. That's what 
[[GetInhertiance]]/[[SetInheritance]] provides.  I choose those names because I 
wanted to place some distance between the generic MOP level operation and the 
specific [[Prototype]] "internal data property" that is present in ordinary 
objects. BTW, "internal data property"  is a formally defined term that means 
private per object state.  Such state is not part of the MOP.

I think in the long run, the new names should reduce confusion, but I could be 
wrong. Regardless, I figured that there would be some controversy about these 
new names and they could easily be [[GetPrototype]]/[[SetPrototype]] but I 
wanted to run it up the flag pole and get reactions.  


> 
>> Added [[[IsExtensible]]/[[PreventExtensions]].
> ES5 had a note mentioning that there was no standard mechanism to set 
> [[Extensible]] from false to true; this new way makes the note unnecessary by 
> design of having internal methods instead of an internal property. OCaps FTW 
> I guess :-)

The MOP only works in terms of methods.  All internal state is defined as parts 
of specific kinds of objects that implement the MOP methods.

> 
>> Replaced [[Get]]/[[Put]] with [[GetP]]/[[SetP]]. At some point we may be 
>> able to rename these as [[Get]]/[[Set]].
> +1 for [[Get]]/[[Set]]. That's the accessor terminology, that's what JS devs 
> are used to. It makes the spec easier to read for them.

yes, I hope to do this but I didn't want to change too much from the current 
Proxy spec. in one step.

> 
>> Eliminated [[GetProperty]], [[CanPut]], [[HasProperty]], [[DefaultValue]].
> So good to see this cleanup :-)
> 
>> Added Keys, [[OwnPropertyKeys]], [[Freeze]], [[Seal]], [[IsFrozen]], 
>> [[IsSealed]].
> For both the enumerations and the layer on top of [[PreventExtension]], I'm 
> uneasy.

So am I and this has been one of the topics in recent public and private 
threads. 


> * [[Enumerate]], [[Keys]] and [[OwnPropertyKeys]] are very close operations
> * So are [[PreventExtensions]]/[[Freeze]]/[[Seal]] on one side and 
> [[IsExtensible]]/[[IsFrozen]]/[[IsSealed]]
> 
> I'm afraid that making them distinct operations increases footgun-ness. 
> [[HasProperty]] has been removed in favored of [[HasOwnProperty]] (which 
> might be removed in favor of only keeping [[GetOwnProperty]], though the 
> conclusion of the discussion was the keep both IIRC) because the former could 
> be "robustly" composed between 

Yes, I agree.  In particular I think [[Enumerate]], [[Keys]], and 
[[OwnPropertyKeys]] should be reduced to a single parameterized trap. Multiple 
traps make it harder to create an internally consistent MOP provider (eg, Proxy 
handler).

> 
> For proxies, [[Extensible]]ity-related operations have invariants so 
> inconsistencies between [[PreventExtensions]], [[Freeze]], [[Seal]], 
> [[IsExtensible]], [[IsFrozen]] and [[IsSealed]] are impossible.
> However, one can legitimately wonder what will happen if a new built-in 
> operation using [[PreventExtensions]] is introduced in a later version of 
> ECMAScript. Let's say experience with     unique/private symbols reveals that 
> the current Object.freeze behavior (whatever it is in regard to symbols) is 
> inappropriate and that adding a new Object.freezeWithDifferentSymbolHandling 
> is introduced. The current pattern suggests that adding new 
> [[FreezeWithDifferentSymbolHandling]]/[[IsFrozenWithDifferentSymbolHandling]] 
> internals will be the way to go.
> I'm not sure it's a good pattern.

I think, TomV and I have tentative agreement that we could eliminate 
[[Freeze]]/[[Seal]]/[[IsFrozen]]//IsSealed]] from the MOP and place equivalent 
abstract operations into 9.3 (generic operations upon objects).  However, 
subsequently I've come around to what I think is better approach.  See 
https://mail.mozilla.org/pipermail/es-discuss/2012-November/026558.html which I 
quote:

Also replace [[PreventExtensions]]/[[IsExtensible]] with 
[[SetIntegrity]](state)//[[GetIntegrity]] where state is one of 
"non-extensible", "sealed", "frozen" and only lower to higher transitions are 
allowed. Also, for proxies this would generate a "notify only" trap.  The 
Object.sealed/freeze/isSealed/isFrozen/preventExtrensions/isExtensible 
functions could then all be implemented in terms of those two traps.

Note that this would all future addition of additional integrity states.  Other 
reasons are discussed in that thread.

> 
> 
> The issue seems worse in footgunness scale for enumeration operations because 
> different operations could yield completely unrelated results. And once 
> again, if it is wanted to add a new enumeration operation on syntax surface, 
> it seems that a new internal operation will be necessary.

Yes I totally agree.

> 
> 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.

Yes, something like this.  My inclination would be to add a hint parameter 
indicating one of the currently known variations. I think it is justified as 
enabling the "handler" to optimize its internal work of collecting the set of 
keys.

> 
> 
>>   • instanceof operator no longer uses an internal method. Instead, 
>> extensible via a @@hasInstance symbol-keyed regular method.
> I don't remember a discussion on this topic, but I think it's an interesting 
> change. Is it for browser APIs?
> 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.

I found wiki material stating that this approach should be taken instead for 
further formalizing the [[HasInstance]] as part of the function part of the 
MOP. You can make @@hasInstance non-configurable, in situations where you care. 
 Just like you would need to do with the prototype property.  Note that 
(some/?) legacy DOM implementations apparently use a non-standard semantics of 
instanceof, so it seems like a necessary MOP extension point.

> 
>> • Defined all of the functions in the @Reflect module corresponding to MOP 
>> internal operations.
> IIRC __proto__ has been agreed to be an data property and there was no 
> Reflect.setPrototypeOf operation in the harmony Reflect module proposal on 
> purpose so that 'delete Object.prototype.__proto__' at any point would be 
> enough to be sure that all [[Prototype]]-setting capabilities are removed.
> So I think the Reflect.setPrototypeOf  should be removed.

Do you want to be able to set __proto__ on DOM objects and other exotic 
objects?  If so, it needs to be part of the MOP.  "In for a penny, in for a 
pound". If we are going to make __proto__ part of the language than we have to 
accommodate just like any other feature.  If you want to be able to disable it 
make deletion of Reflect.setPrototypeOf be the switch.  Or define a new 
function for doing it.  But I don't think we should be bending the MOP to 
accommodate idioms like deleting __proto__..  Remember, the first point above.  
[[SetInheritance]] is a generic operation, only some objects implement via a 
[[Prototype]] internal data property.


Allen

> 
> David
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to