Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Ok, somehow I had completely missed 9.3.10 TestIntegrityLevel (O, level) which does exactly the derived computation for sealed and frozen objects. I think André is right though about the bug in 8.3.3 step 2.a. Cheers, Tom 2013/3/17 Allen Wirfs-Brock al...@wirfs-brock.com Tom recently suggested that that we really don't need MOP-level or trap operations from freezing, sealing and testing those states. Also, there seems to be minimal support for having explicit freeze/sealed integrity states or for adding integrity integrity states. So I'm probably going to go make to an style design. We'll only have [[IsExtensible]] and [[PreventExtensions]] MOP/trap/Reflect operations. Object.freeze/seal/isFrozen/isSealed will be derived operations. Allen On Mar 17, 2013, at 10:16 AM, Tom Van Cutsem wrote: Hi, Allen's latest draft (Rev. 14) contains the change where [[Freeze]],[[Seal]] and [[PreventExtensions]] have been consolidated into [[HasIntegrity]]/[[SetIntegrity]]. While no changes were made to the Proxy API (i.e. no has/getIntegrity traps yet), the definition of Object.{freeze,seal,preventExtensions} did change, and this is sufficient to expose an incompatibility with ES5, namely: Object.isFrozen(Object.preventExtensions({})) // true in ES5, false in ES6 Rev14 draft I still feel like the consolidation isn't worth this incompatibility. Allen, could you clarify what your intent is? Is it your intent that this incompatibility will be fixed with further spec changes? Cheers, Tom 2013/2/21 Brendan Eich bren...@mozilla.com Tom Van Cutsem wrote: That said, I don't think this is enough evidence either for or against the breaking change. I have a hard time believing we can break ES5. It has been shipping for years (plural, at least in one case) in major browsers that evergreen their user bases. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Allen and I had a conversation that clarified things. Essentially, the plan is to only have [[PreventExtensions]]/[[IsExtensible]] internal MOP methods, and to only have the corresponding preventExtensions/isExtensible traps for proxies. Proxies won't have isSealed, isFrozen, seal and frozen traps and there will be no corresponding Reflect.{isSealed,isFrozen,seal,frozen} methods. Calling Object.freeze(proxy) instead triggers the proxy's getOwnPropertyNames trap and then updates each own property of the proxy via defineProperty. Similar story for Object.isFrozen(proxy). Pro: - We get rid of 4 MOP methods ([[Freeze]],[[Seal]],[[IsFrozen]],[[IsSealed]]). This simplifies both the internal MOP and the Proxy API. - Freezing and sealing always behave consistently, even in the face of proxies. There's no chance for a proxy to implement multiple traps inconsistently. Con: - Object.freeze(proxy) and Object.isFrozen(proxy) must observably iterate over all own properties of the proxy (same for seal/isSealed). Cheers, Tom 2013/3/18 Tom Van Cutsem tomvc...@gmail.com Ok, somehow I had completely missed 9.3.10 TestIntegrityLevel (O, level) which does exactly the derived computation for sealed and frozen objects. I think André is right though about the bug in 8.3.3 step 2.a. Cheers, Tom 2013/3/17 Allen Wirfs-Brock al...@wirfs-brock.com Tom recently suggested that that we really don't need MOP-level or trap operations from freezing, sealing and testing those states. Also, there seems to be minimal support for having explicit freeze/sealed integrity states or for adding integrity integrity states. So I'm probably going to go make to an style design. We'll only have [[IsExtensible]] and [[PreventExtensions]] MOP/trap/Reflect operations. Object.freeze/seal/isFrozen/isSealed will be derived operations. Allen On Mar 17, 2013, at 10:16 AM, Tom Van Cutsem wrote: Hi, Allen's latest draft (Rev. 14) contains the change where [[Freeze]],[[Seal]] and [[PreventExtensions]] have been consolidated into [[HasIntegrity]]/[[SetIntegrity]]. While no changes were made to the Proxy API (i.e. no has/getIntegrity traps yet), the definition of Object.{freeze,seal,preventExtensions} did change, and this is sufficient to expose an incompatibility with ES5, namely: Object.isFrozen(Object.preventExtensions({})) // true in ES5, false in ES6 Rev14 draft I still feel like the consolidation isn't worth this incompatibility. Allen, could you clarify what your intent is? Is it your intent that this incompatibility will be fixed with further spec changes? Cheers, Tom 2013/2/21 Brendan Eich bren...@mozilla.com Tom Van Cutsem wrote: That said, I don't think this is enough evidence either for or against the breaking change. I have a hard time believing we can break ES5. It has been shipping for years (plural, at least in one case) in major browsers that evergreen their user bases. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Hi, Allen's latest draft (Rev. 14) contains the change where [[Freeze]],[[Seal]] and [[PreventExtensions]] have been consolidated into [[HasIntegrity]]/[[SetIntegrity]]. While no changes were made to the Proxy API (i.e. no has/getIntegrity traps yet), the definition of Object.{freeze,seal,preventExtensions} did change, and this is sufficient to expose an incompatibility with ES5, namely: Object.isFrozen(Object.preventExtensions({})) // true in ES5, false in ES6 Rev14 draft I still feel like the consolidation isn't worth this incompatibility. Allen, could you clarify what your intent is? Is it your intent that this incompatibility will be fixed with further spec changes? Cheers, Tom 2013/2/21 Brendan Eich bren...@mozilla.com Tom Van Cutsem wrote: That said, I don't think this is enough evidence either for or against the breaking change. I have a hard time believing we can break ES5. It has been shipping for years (plural, at least in one case) in major browsers that evergreen their user bases. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
The incompatibility you've noticed is just a spec bug in [[HasIntegrity]]. In step 2a of 8.3.3, the value of [[Extensible]] needs to be inverted. With that change applied, the code snippet will return `true`. - André Hi, Allen's latest draft (Rev. 14) contains the change where [[Freeze]],[[Seal]] and [[PreventExtensions]] have been consolidated into [[HasIntegrity]]/[[SetIntegrity]]. While no changes were made to the Proxy API (i.e. no has/getIntegrity traps yet), the definition of Object.{freeze,seal,preventExtensions} did change, and this is sufficient to expose an incompatibility with ES5, namely: Object.isFrozen(Object.preventExtensions({})) // true in ES5, false in ES6 Rev14 draft I still feel like the consolidation isn't worth this incompatibility. Allen, could you clarify what your intent is? Is it your intent that this incompatibility will be fixed with further spec changes? Cheers, Tom 2013/2/21 Brendan Eich brendan at mozilla.com https://mail.mozilla.org/listinfo/es-discuss / Tom Van Cutsem wrote: // // That said, I don't think this is enough evidence either for or against // the breaking change. // // // I have a hard time believing we can break ES5. It has been shipping for // years (plural, at least in one case) in major browsers that evergreen their // user bases. // // /be / ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Tom recently suggested that that we really don't need MOP-level or trap operations from freezing, sealing and testing those states. Also, there seems to be minimal support for having explicit freeze/sealed integrity states or for adding integrity integrity states. So I'm probably going to go make to an style design. We'll only have [[IsExtensible]] and [[PreventExtensions]] MOP/trap/Reflect operations. Object.freeze/seal/isFrozen/isSealed will be derived operations. Allen On Mar 17, 2013, at 10:16 AM, Tom Van Cutsem wrote: Hi, Allen's latest draft (Rev. 14) contains the change where [[Freeze]],[[Seal]] and [[PreventExtensions]] have been consolidated into [[HasIntegrity]]/[[SetIntegrity]]. While no changes were made to the Proxy API (i.e. no has/getIntegrity traps yet), the definition of Object.{freeze,seal,preventExtensions} did change, and this is sufficient to expose an incompatibility with ES5, namely: Object.isFrozen(Object.preventExtensions({})) // true in ES5, false in ES6 Rev14 draft I still feel like the consolidation isn't worth this incompatibility. Allen, could you clarify what your intent is? Is it your intent that this incompatibility will be fixed with further spec changes? Cheers, Tom 2013/2/21 Brendan Eich bren...@mozilla.com Tom Van Cutsem wrote: That said, I don't think this is enough evidence either for or against the breaking change. I have a hard time believing we can break ES5. It has been shipping for years (plural, at least in one case) in major browsers that evergreen their user bases. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Tom Van Cutsem wrote: That said, I don't think this is enough evidence either for or against the breaking change. I have a hard time believing we can break ES5. It has been shipping for years (plural, at least in one case) in major browsers that evergreen their user bases. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
2013/2/18 Andreas Rossberg rossb...@google.com On 16 February 2013 20:36, Allen Wirfs-Brock al...@wirfs-brock.com wrote: It's to simplify the MOP and that simplification is directly reflected as a simplification to the Proxy hander interface. Instead of 6 traps (preventExtensions, isExtensible, freeze, isFrozen, seal, isSealed) only two are needed. Also, having an explicit frozen object state simplifies some of the object invariants which would otherwise perform explicitly specified accesses to the target object which would be observable (if the target is itself a proxy). Well, that is either a breaking change, such that implementations can not actually be lazy about it, or it doesn't really remove complexity, since you still need to infer the state as a fallback (i.e., it's just an optimisation). I don't necessarily oppose making that breaking change, but we have to be aware that, even though it's an optimisation, the change is yet another complication of the object model. The additional state modifies the meaning of per-property descriptors on a second level. IIUC, defineProperty now has to check against that state, and getOwnPropertyDescriptor somehow has to take it into account, too. For direct proxies, the respective traps have to extend their validation logic. Overall, not a simplification, as far as I can see. I've been thinking some more about get/setIntegrity and I've come to the same conclusion. While get/setIntegrity gets rid of 4 traps (sealed/isSealed/frozen/isFrozen), it does so at the expense of extra complexity in other parts of the MOP, in particular, adding yet more state to check and update in [[GetOwnProperty]] and [[DefineOwnProperty]]. Allen, in light of this, wouldn't you agree that it's better to keep the extra traps? Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
On Feb 20, 2013, at 9:24 AM, Tom Van Cutsem wrote: 2013/2/18 Andreas Rossberg rossb...@google.com On 16 February 2013 20:36, Allen Wirfs-Brock al...@wirfs-brock.com wrote: It's to simplify the MOP and that simplification is directly reflected as a simplification to the Proxy hander interface. Instead of 6 traps (preventExtensions, isExtensible, freeze, isFrozen, seal, isSealed) only two are needed. Also, having an explicit frozen object state simplifies some of the object invariants which would otherwise perform explicitly specified accesses to the target object which would be observable (if the target is itself a proxy). Well, that is either a breaking change, such that implementations can not actually be lazy about it, or it doesn't really remove complexity, since you still need to infer the state as a fallback (i.e., it's just an optimisation). I don't necessarily oppose making that breaking change, but we have to be aware that, even though it's an optimisation, the change is yet another complication of the object model. The additional state modifies the meaning of per-property descriptors on a second level. IIUC, defineProperty now has to check against that state, and getOwnPropertyDescriptor somehow has to take it into account, too. For direct proxies, the respective traps have to extend their validation logic. Overall, not a simplification, as far as I can see. I've been thinking some more about get/setIntegrity and I've come to the same conclusion. While get/setIntegrity gets rid of 4 traps (sealed/isSealed/frozen/isFrozen), it does so at the expense of extra complexity in other parts of the MOP, in particular, adding yet more state to check and update in [[GetOwnProperty]] and [[DefineOwnProperty]]. Allen, in light of this, wouldn't you agree that it's better to keep the extra traps? Actually, no. Reducing API complexity (in this case, the Proxy handler API) at the expense of a little bit of added spec. complexity seems like a very reasonable trade-off. Plus, we are talking about spec. complexity, not necessarily implementation complexity. An implementation is free to distribute the complexity however it chooses. For example, if an implementation always sets all of an objet's property descriptors to configurable: false when [[SetIntegrity]](frozen) is performed (which Object.freeze is specified to do in ES5) then there shouldn't be any extra work that needs to be done in the ordinary implementations of [[GetOwnProperty]] or [[DefineOwnProperty]]. Also, I'm concerned that we have been overloading the meaning of the [[Extensible]] state by hanging other meanings off of it, because it is the only integrity state we currently have at the object level. For example, we have tentative agreement at the timevalue of Date objects can not be modified if [[Extensible]] is false and that RegExp.prototype.compile will not update an RegExp instance if [[Extensible]] is false. Both of these seem like things that would be better to associate with an explicit frozen object state. We are also, from ES5, using [[Extensible]] to control whether [[Prototype]] can be modified. This is a case where I think a new state might be appropriate as it seems very reasonable for an object to want to fix [[Prototype]] but still allow own properties to be added Finally, I still think we should further consider the feasibly of a breaking change where Object.preventExtensions(obj); for ( let k of Object.getOwnPropertyKeys(obj)) Object.defineProperty(obj,k,{configurable:false}); is no longer equivalent to Object.freeze(obj) in terms of causing Object.isFrozen(obj) to return false. I think I previously asked if anybody is aware of situations where Object.isFrozen tests are done but Object.freeze is not used to set objects to the frozen state. So far, no answers. Anybody? Allen Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Allen Wirfs-Brock wrote: I think I previously asked if anybody is aware of situations where Object.isFrozen tests are done but Object.freeze is not used to set objects to the frozen state. So far, no answers. Anybody? Speaking just from my own experience as a user of ES5, I have not found `Object.isFrozen` to be helpful yet. If I want to see if I can configure a property, I check `Object.isExtensible` and `!Object.prototype.hasOwnProperty.call(obj, key) || Object.getOwnPropertyDescriptor(obj, key).configurable`. `Object.isFrozen` and `Object.isSealed` don't really seem that helpful to me for the very reasons you've discussed: They don't represent any real object state, so they don't accurately tell me what can be done with an object. If I could I would argue in favor of their removal, though I know it's too late for that. I would be curious to see legitimate uses of `isFrozen` and `isSealed` in existing code if anyone has anything to offer. Nathan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
On Wed, Feb 20, 2013 at 11:52 AM, Nathan Wall nathan.w...@live.com wrote: `Object.isFrozen` and `Object.isSealed` don't really seem that helpful to me for the very reasons you've discussed: They don't represent any real object state, so they don't accurately tell me what can be done with an object. If I could I would argue in favor of their removal, though I know it's too late for that. I would be curious to see legitimate uses of `isFrozen` and `isSealed` in existing code if anyone has anything to offer. I just took a look at uses of Object.isFrozen in Caja and I find that all but one are either in tests (test that something is frozen) or in sanity checks (if this isn't frozen, do not proceed further, or freeze it and warn). The remaining one is in a WeakMap abstraction used for trademarking: an object cannot be given a trademark after it is frozen. (The rationale here, while not written down, I assume is that a defensive object's “interface” should not change, and it is an implementation detail that this particular information is not stored in the object.) There is a comment there suggesting we might strengthen this check to only permitting _extensible_ objects to be marked. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Le 20/02/2013 21:08, Kevin Reid a écrit : On Wed, Feb 20, 2013 at 11:52 AM, Nathan Wall nathan.w...@live.com mailto:nathan.w...@live.com wrote: `Object.isFrozen` and `Object.isSealed` don't really seem that helpful to me for the very reasons you've discussed: They don't represent any real object state, so they don't accurately tell me what can be done with an object. If I could I would argue in favor of their removal, though I know it's too late for that. I would be curious to see legitimate uses of `isFrozen` and `isSealed` in existing code if anyone has anything to offer. I just took a look at uses of Object.isFrozen in Caja and I find that all but one are either in tests (test that something is frozen) or in sanity checks (if this isn't frozen, do not proceed further, or freeze it and warn). The remaining one is in a WeakMap abstraction used for trademarking: an object cannot be given a trademark after it is frozen. (The rationale here, while not written down, I assume is that a defensive object's interface should not change, and it is an implementation detail that this particular information is not stored in the object.) There is a comment there suggesting we might strengthen this check to only permitting _extensible_ objects to be marked. And in an ES6 world, you'll probably use an actual WeakMap anyway? Thanks for sharing this experience from Caja, David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
On Wed, Feb 20, 2013 at 12:15 PM, David Bruant bruan...@gmail.com wrote: And in an ES6 world, you'll probably use an actual WeakMap anyway? Using an actual WeakMap does not change matters: the intent is that after Object.freeze(o), you can't add new trademarks to o. Since the trademark info is not stored on the object but in the WeakMap (whether emulated or actual), we have to add an explicit test. If 'private properties' (in whatever form they come to ES6) were available to us, then it would be natural to use them instead for this purpose (at least, so it seems to me at the moment) and so we would not need a test since non-extensibility would presumably reject the addition of a new private property. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
(I do not yet have an overall opinion about get/setIntegrity. Here, I'm just answering and clarifying, not advocating.) On Wed, Feb 20, 2013 at 10:57 AM, Allen Wirfs-Brock al...@wirfs-brock.comwrote: [...] Also, I'm concerned that we have been overloading the meaning of the [[Extensible]] state by hanging other meanings off of it, because it is the only integrity state we currently have at the object level. For example, we have tentative agreement at the timevalue of Date objects can not be modified if [[Extensible]] is false and that RegExp.prototype.compile will not update an RegExp instance if [[Extensible]] is false. Both of these seem like things that would be better to associate with an explicit frozen object state. Another instance of the same issue in a different guise is the restriction in Object.observe (for ES7) that you cannot obtain from a frozen object the right to notify its observers. In this case, in order to be more permissive, we did attach the restriction to frozenness rather than just extensibility. However, when frozenness is a complex test for a pattern of restrictions that may or may not be accidental, this seems weird. In other words, if an object is purposely frozen, no problem. But let's say that in v1 of a program, object A is non-extensible, its foo property is non-configurable, non-writable, and its bar property is writable. A later refactoring realizes it doesn't need the bar property, and so deletes it. It is weird that this would break previously correct code to obtain the right to notify observers. We are also, from ES5, using [[Extensible]] to control whether [[Prototype]] can be modified. This is a case where I think a new state might be appropriate as it seems very reasonable for an object to want to fix [[Prototype]] but still allow own properties to be added While sensible in theory, I don't think that case is worth yet another state bit. If, like Object.observe, we had attached this restriction to frozenness, we could not consider attaching this to an explicit frozenness bit. Finally, I still think we should further consider the feasibly of a breaking change where Object.preventExtensions(obj); for ( let k of Object.getOwnPropertyKeys(obj)) Object.defineProperty(obj,k,{configurable:false}); is no longer equivalent to Object.freeze(obj) in terms of causing Object.isFrozen(obj) to return false. I think I previously asked if anybody is aware of situations where Object.isFrozen tests are done but Object.freeze is not used to set objects to the frozen state. So far, no answers. Anybody? I know of no uses of Object.isFrozen beyond those Kevin lists. None of these would be broken by this change. As for the rationale for the trademark restriction, more on that in a separate email. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
Allen Wirfs-Brock wrote: Actually, no. Reducing API complexity (in this case, the Proxy handler API) at the expense of a little bit of added spec. complexity seems like a very reasonable trade-off. Plus, we are talking about spec. complexity, not necessarily implementation complexity. Sure, but the spec is the first implementation. If implementors will not add another state bit (I predict they won't) then the spec is doing a disservice here. The Proxy API is complex already, due to ES5 in this case. It is not that much less complex with setIntegrity. I don't think the trade-off is worth it, and I suggest the all implementors ignore the spec complexity condition is one to avoid. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: get/setIntegrity trap (Was: A case for removing the seal/freeze/isSealed/isFrozen traps)
2013/2/20 Allen Wirfs-Brock al...@wirfs-brock.com Finally, I still think we should further consider the feasibly of a breaking change where Object.preventExtensions(obj); for ( let k of Object.getOwnPropertyKeys(obj)) Object.defineProperty(obj,k,{configurable:false}); is no longer equivalent to Object.freeze(obj) in terms of causing Object.isFrozen(obj) to return false. I think I previously asked if anybody is aware of situations where Object.isFrozen tests are done but Object.freeze is not used to set objects to the frozen state. So far, no answers. Anybody? I did a little code search via GitHub on uses of Object.isFrozen in JS code. The large majority seems to occur in test cases (incl. Test262) or libraries involving ES5 shims for ES3. There's no doubt this breaking change will get noticed, as Test262 contains code such as: assertEq(Object.isFrozen(Object.preventExtensions({})), true); However, here and there you can find some code that branches on frozenness, although it's not always clear what the rationale behind it is, e.g.: https://github.com/petekinnecom/portfolio_chaplin/blob/b241300968fe6011c54548f24e0c8cfcd5d6d663/app/views/tube_view.coffee#L39 That said, I don't think this is enough evidence either for or against the breaking change. Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On 16 February 2013 20:36, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Feb 14, 2013, at 11:46 AM, Andreas Rossberg wrote: On 14 February 2013 01:05, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Where do without, means replaced with set/getIntegrity traps and objects have explicit internal state whose value is one of normal/non-extensible/sealed/frozen (and possibly) fixed-inheritance between normal and non-extensible to freeze [[Prototype]]). [[SetIntegrity]] can increase the integrity level but not decrease it. The perf and invariant complexity concerns come from the fact that the sealed/frozen status of an object can only be inferred by inspecting all of its methods. Having an explicit state eliminates the need to do this inspection. It also simplifies the MOP by merging all of the extensible/sealed/frozen related MOP operations into only two ops. But, one way or another, these object state transitions must be accounted for in the MOP. For this to fly, implementation have to be able to expand their current 1 bit of of extensible state to at least 2 bits (3 would be better). Or perhaps not, I suppose we could just introduce the MOP level changes and a lazy implementation could continue to infer the state by examining all its methods. I still must be missing something. Why should the language be changed when the proposed change is equivalent anyway? Why is this an optimisation that the spec should worry about instead of the implementations? It's to simplify the MOP and that simplification is directly reflected as a simplification to the Proxy hander interface. Instead of 6 traps (preventExtensions, isExtensible, freeze, isFrozen, seal, isSealed) only two are needed. Also, having an explicit frozen object state simplifies some of the object invariants which would otherwise perform explicitly specified accesses to the target object which would be observable (if the target is itself a proxy). Well, that is either a breaking change, such that implementations can not actually be lazy about it, or it doesn't really remove complexity, since you still need to infer the state as a fallback (i.e., it's just an optimisation). I don't necessarily oppose making that breaking change, but we have to be aware that, even though it's an optimisation, the change is yet another complication of the object model. The additional state modifies the meaning of per-property descriptors on a second level. IIUC, defineProperty now has to check against that state, and getOwnPropertyDescriptor somehow has to take it into account, too. For direct proxies, the respective traps have to extend their validation logic. Overall, not a simplification, as far as I can see. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: A case for removing the seal/freeze/isSealed/isFrozen traps
David Bruant wrote: ... Security is very loaded with emotions of people afraid to have their password stolen and cyber attacks. It's also loaded with the notion of human safety and human integrity which, as human beings are sensitive to. Maybe I should start using a different word... Great explanation, David. That's everything I've wanted to say but haven't been able to find the words. Thanks for this! Also, I've started using the word integrity to describe this kind of code, to get away from the loadedness of security. For instance, Mark Miller's low-integrity puzzle[1]: function makeTable() { var array = []; return Object.freeze({ add: function(v) { array.push(v); }, store: function(i, v) { array[i] = v; }, get: function(i) { return array[i]; } }); } as a high-integrity function: var freeze = Object.freeze, push = Function.prototype.call.bind(Array.prototype.push); function makeTable() { var array = []; return freeze({ add: function(v) { push(array, v); }, store: function(i, v) { array[i 0] = v; }, get: function(i) { return array[i 0]; } }); } Of course, you don't want to write this way all the time. I think it's good for library code. [1] http://mail.mozilla.org/pipermail/es-discuss/2011-November/017964.html Nathan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
as a high-integrity function: var freeze = Object.freeze, push = Function.prototype.call.bind(Array.prototype.push); function makeTable() { var array = []; return freeze({ add: function(v) { push(array, v); }, store: function(i, v) { array[i 0] = v; }, get: function(i) { return array[i 0]; } }); } Careful there, you're not done!-) With nodejs, adding the following var table = makeTable(); table.add(1); table.add(2); table.add(3); var secret; Object.defineProperty(Array.prototype,42,{get:function(){ secret = this;}}); table.get(42); console.log(secret); secret[5] = me, too!; console.log( table.get(5) ); to your code prints $ node integrity.js [ 1, 2, 3 ] me, too! Couldn't resist, Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: A case for removing the seal/freeze/isSealed/isFrozen traps
Claus Reinke wrote: Careful there, you're not done!-) With nodejs, adding the following var table = makeTable(); table.add(1); table.add(2); table.add(3); var secret; Object.defineProperty(Array.prototype,42,{get:function(){ secret = this;}}); table.get(42); console.log(secret); secret[5] = me, too!; console.log( table.get(5) ); to your code prints $ node integrity.js [ 1, 2, 3 ] me, too! Couldn't resist, Claus Nice! This is not something I had considered. Aside from freezing Array.prototype, I can only really think of one solution: not use an array. var create = Object.create, freeze = Object.freeze, push = Function.prototype.call.bind(Array.prototype.push); function makeTable() { var array = create(null); return freeze({ add: function(v) { push(array, v); }, store: function(i, v) { array[i 0] = v; }, get: function(i) { return array[i 0]; } }); } I suppose the array isn't really needed since we're not using methods inherited from Array.prototype. Downside: Browsers won't know to optimize the object as an array. (Side note: Mark's original post was in the context of frozen Array.prototype on non-compliant implementations which allow writing to inherited non-writable properties. I find this a fun exercise without frozen Array.prototype, though.) Nathan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On Mon, Feb 18, 2013 at 2:27 PM, Nathan Wall nathan.w...@live.com wrote: Claus Reinke wrote: Careful there, you're not done!-) With nodejs, adding the following var table = makeTable(); table.add(1); table.add(2); table.add(3); var secret; Object.defineProperty(Array.prototype,42,{get:function(){ secret = this;}}); table.get(42); console.log(secret); secret[5] = me, too!; console.log( table.get(5) ); to your code prints $ node integrity.js [ 1, 2, 3 ] me, too! Couldn't resist, Claus Nice! This is not something I had considered. Aside from freezing Array.prototype, I can only really think of one solution: not use an array. var create = Object.create, freeze = Object.freeze, push = Function.prototype.call.bind(Array.prototype.push); function makeTable() { var array = create(null); return freeze({ add: function(v) { push(array, v); }, store: function(i, v) { array[i 0] = v; }, In all seriousness, I suggest array[+i] = v; rather than array[i 0] = v; because the latter is too verbose to become a habit. I recommend this even though I agree that the more verbose one has the better semantics. get: function(i) { return array[i 0]; } }); } I suppose the array isn't really needed since we're not using methods inherited from Array.prototype. Downside: Browsers won't know to optimize the object as an array. (Side note: Mark's original post was in the context of frozen Array.prototype on non-compliant implementations which allow writing to inherited non-writable properties. I find this a fun exercise without frozen Array.prototype, though.) Note that Jorge's attack at https://mail.mozilla.org/pipermail/es-discuss/2011-November/017979.htmlworks even on compliant browsers. Nathan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On Feb 14, 2013, at 11:46 AM, Andreas Rossberg wrote: On 14 February 2013 01:05, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Where do without, means replaced with set/getIntegrity traps and objects have explicit internal state whose value is one of normal/non-extensible/sealed/frozen (and possibly) fixed-inheritance between normal and non-extensible to freeze [[Prototype]]). [[SetIntegrity]] can increase the integrity level but not decrease it. The perf and invariant complexity concerns come from the fact that the sealed/frozen status of an object can only be inferred by inspecting all of its methods. Having an explicit state eliminates the need to do this inspection. It also simplifies the MOP by merging all of the extensible/sealed/frozen related MOP operations into only two ops. But, one way or another, these object state transitions must be accounted for in the MOP. For this to fly, implementation have to be able to expand their current 1 bit of of extensible state to at least 2 bits (3 would be better). Or perhaps not, I suppose we could just introduce the MOP level changes and a lazy implementation could continue to infer the state by examining all its methods. I still must be missing something. Why should the language be changed when the proposed change is equivalent anyway? Why is this an optimisation that the spec should worry about instead of the implementations? It's to simplify the MOP and that simplification is directly reflected as a simplification to the Proxy hander interface. Instead of 6 traps (preventExtensions, isExtensible, freeze, isFrozen, seal, isSealed) only two are needed. Also, having an explicit frozen object state simplifies some of the object invariants which would otherwise perform explicitly specified accesses to the target object which would be observable (if the target is itself a proxy). Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On Feb 14, 2013, at 1:14 AM, Tom Van Cutsem wrote: 2013/2/14 Allen Wirfs-Brock al...@wirfs-brock.com On Feb 13, 2013, at 12:53 PM, David Bruant wrote: Interesting. So what would happen when calling Object.isFrozen on a proxy? Would Object.isFrozen/isSealed/isExtensible reach out directly to the target? or a unique state trap returning a string for all of them? (state is too generic of a name, but you get the idea) This is a question regarding proxy design, rather than the MOP. Either get/setIntegrity traps to the handler or it forwards directly to the target. That's would be a design issue for Tom, but my starting point is to simply follow the current design decisions made for [[PreventExtensions]]/[[IsExtensible]] A get/setIntegrity trap with the invariant constraints of isExtensible/preventExtensions would be the obvious path to take. One thing that remains unclear to me: if the state of an object becomes explicit, we introduce the risk for this state to become inconsistent with the state from which it is derived. For example, setting the integrity of an object to frozen must still make all own properties non-configurable, i.e. Reflect.setIntegrity(obj, frozen) should have the same effect as Object.freeze(obj) yes, Object.freeze(obj) would be specified as performing: obj.[[SetIntegrity]](frozen) Likewise, turning the last configurable property of a non-extensible object into a non-configurable property should automagically change the state to frozen, i.e. Object.defineProperty(obj, lastProperty, { configurable: false }) // must update internal state as well as the property Reflect.getIntegrity(obj) === frozen If I was starting fresh, I would say that Object.isFrozen(obj) is true only if Object.freeze(obj) (or equivalent Reflect.setIntegrity) has previous been performed and that Object.preventExtensions() followed by setting every property to non-configurable is not equivalent to performing Object.freeze. I wonder if we can make that change for ES6 without breaking anything. Does anybody know of code that does Object.isFrozen(obj) checks without also having the expectation that obj would have been explicitly frozen using Object.freeze? Will this not just shift the current complexity someplace else? Well, it means that for 100% backwards compatibility, Object.isFrozen would have to be something like: 1. Let state = obj.[[GetIntegrity]](); 2 If state is frozen return true; 3 If state is sealed or non-extensible, then return true if all properties are non-configurable and non-writable 4 return false. The real complexity saving is in simplifying the MOP/Proxy handler interface and also in making Proxy invariants only sensitive to the explicit integrity state of an object. Regardless on the final decision on (full) notification proxies, maybe these operations (isSealed/isFrozen) could have notification trap. The invariant is that the answer has to be the target one (all the time), so the trap return value is irrelevant. Like the getPrototypeOf trap. Right, one way or another these operations need to be part of the MOP. If we go for get/setIntegrity I wouldn't re-introduce all the derived operations as notification traps. Then we might as well leave things the way they are. I meant either get/setIntegrity or isExtensible/preventExtensions/isFrozen/freeze/isSealed/seal need to be part of the MOP. If we have get/setIntegrity we don't need the others (at the MOP/proxy trap level) Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Le 16/02/2013 23:31, Allen Wirfs-Brock a écrit : Will this not just shift the current complexity someplace else? Well, it means that for 100% backwards compatibility, Object.isFrozen would have to be something like: 1. Let state = obj.[[GetIntegrity]](); 2 If state is frozen return true; 3 If state is sealed or non-extensible, then return true if all properties are non-configurable and non-writable nit: You can save the state to frozen before returning true. 4 return false. The real complexity saving is in simplifying the MOP/Proxy handler interface and also in making Proxy invariants only sensitive to the explicit integrity state of an object. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
I've worked a lot with ECMAScript5 features in last two years, and I must say I never found a good use case for Object.freeze/seal/preventExtensions, it actually raised more issues than it actually helped (those few times when I decided to use it). Currently I think that's not JavaScript'y approach and use cases mentioning untrusted parties sounds logical just in theory, in practice when actually we never include untrusted modules in our code base does not make much sense. However, main point I want to raise is that several times I had a use case for very close functionality, that with current API seem not possible: I'd like to be able to *prevent accidental object extensions*. I want to control all enumerable properties of the object, so they can only be set via defineProperty, but any direct assignment of non existing prop e.g. 'x.notDefinedYet = value' will throw. Imagine some ORM implementation, that via setters propagates changes to underlying persistent layer, at this time we cannot prevent accidental property sets that may occur before property was actually defined (therefore not caught by the setter) I assume that proxies will make such functionality possible, but maybe some Object.preventUndefinedExtensions will be even better. Brendan Eich-3 wrote: Andreas Rossberg wrote: On 14 February 2013 19:16, David Bruantbruan...@gmail.com wrote: Le 14/02/2013 18:11, Andreas Rossberg a écrit : You're being vastly over-optimistic about the performance and the amount of optimisation that can realistically be expected for proxies. Proxies are inherently unstructured, higher-order, and effectful, which defeats most sufficiently simple static analyses. A compiler has to work much, much harder to get useful results. Don't expect anything anytime soon. var handler = {set: function(){throw new TypeError}} var p = new Proxy({a: 32}, handler); p.a; It's possible *at runtime* to notice that the handler of p doesn't have a get trap, optimize p.[[Get]] as target.[[Get]] and guard this optimization on handler modifications. Obviously, do that only if the code is hot. I feel it's not that much work than what JS engines do currently and the useful result is effectively getting rid of the forwarding overhead. Is this vastly over-optimistic? Yes. Proxies hook into many different basic operations, and there are many special cases you could potentially optimise for each of them, many of which don't come for free. I very much doubt that any vendor currently has serious plans to go down that rathole instead of spending their energy elsewhere. Certainly not before it is clear how (and how much) proxies will actually be used in practice. You're right in general, and we have not optimized, e.g. inlining scripted trap calls. We did do something special for our new DOM bindings I wanted to pass along, in case anyone is interested: https://bugzilla.mozilla.org/show_bug.cgi?id=769911 Thanks to bz for the link. This is yet another inline cache specialization for expandos on nodelists. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss - Mariusz Nowak https://github.com/medikoo -- View this message in context: http://old.nabble.com/A-case-for-removing-the-seal-freeze-isSealed-isFrozen-traps-tp35013883p35026595.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
I like this direction: it would distinguish the user-level operation _assignment_ from the meta-level operation _definition_. I’m not sure where `delete` fits in, but it’s much less common, so less of a potential problem. On Feb 15, 2013, at 11:03 , Mariusz Nowak medikoo+mozilla@medikoo.com wrote: I've worked a lot with ECMAScript5 features in last two years, and I must say I never found a good use case for Object.freeze/seal/preventExtensions, it actually raised more issues than it actually helped (those few times when I decided to use it). Currently I think that's not JavaScript'y approach and use cases mentioning untrusted parties sounds logical just in theory, in practice when actually we never include untrusted modules in our code base does not make much sense. However, main point I want to raise is that several times I had a use case for very close functionality, that with current API seem not possible: I'd like to be able to *prevent accidental object extensions*. I want to control all enumerable properties of the object, so they can only be set via defineProperty, but any direct assignment of non existing prop e.g. 'x.notDefinedYet = value' will throw. Imagine some ORM implementation, that via setters propagates changes to underlying persistent layer, at this time we cannot prevent accidental property sets that may occur before property was actually defined (therefore not caught by the setter) I assume that proxies will make such functionality possible, but maybe some Object.preventUndefinedExtensions will be even better. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Le 15/02/2013 11:03, Mariusz Nowak a écrit : I've worked a lot with ECMAScript5 features in last two years, and I must say I never found a good use case for Object.freeze/seal/preventExtensions, it actually raised more issues than it actually helped (those few times when I decided to use it). Currently I think that's not JavaScript'y approach and use cases mentioning untrusted parties sounds logical just in theory, in practice when actually we never include untrusted modules in our code base does not make much sense. However, main point I want to raise is that several times I had a use case for very close functionality, that with current API seem not possible: I'd like to be able to *prevent accidental object extensions*. If something *accidental* can happen, then untrusted parties is more than theorical ;-) Brendan says it better [1]: In a programming-in-the-large setting, a writable data property is inviting Murphy's Law. I'm not talking about security in a mixed-trust environment specifically. Large programs become mixed trust, even when it's just me, myself, and I (over time) hacking the large amount of code. Security and untrusted parties aren't about terrorists groups trying to hack your application to get a copy of your database or corrupt it or your choice to use some code downloaded from a dark-backgrounded website. They're about you trying to meet a deadline and not having time to read carefully the documentation and comments of every single line of modules you're delegating to. Trust isn't an all-or-nothing notion. Anytime I say untrusted, I should probably say partially trusted instead. Trust also changes over time, mostly because as times passes, our brains forget the invariants and assumptions we baked in our code and if those aren't enforced at compile time or runtime, we'll probably violate them at one point or another and thus create bugs. Or we just make mistakes, because we're human and that's exactly the case you're explaining. Security and untrusted parties are about our inability as human beings to remember everything we do and our inability to be perfect. Any security mechanism is a mechanism to protect against hostile outsiders but also and probably mostly ourselves over time. It is usually not considered so, but separation of concerns is a security mechanism in my opinion. So are most object-oriented so-called good practices. Security is very loaded with emotions of people afraid to have their password stolen and cyber attacks. It's also loaded with the notion of human safety and human integrity which, as human beings are sensitive to. Maybe I should start using a different word... I want to control all enumerable properties of the object, so they can only be set via defineProperty, but any direct assignment of non existing prop e.g. 'x.notDefinedYet = value' will throw. Imagine some ORM implementation, that via setters propagates changes to underlying persistent layer, at this time we cannot prevent accidental property sets that may occur before property was actually defined (therefore not caught by the setter) I assume that proxies will make such functionality possible, but maybe some Object.preventUndefinedExtensions will be even better. The problem is that there are probably dozens of use cases like yours [2] and the Object built-in can't welcome them all. Hence proxies as an extension mechanism of any random micro-abstraction (as Andreas Rossberg puts it ;-) ) David [1] https://mail.mozilla.org/pipermail/es-discuss/2013-February/028724.html [2] When I learned JS, how many time did I mistyped .innerHTML and wasted hours not understanding where some undefined string in my UI came from. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
David, that's great clarification, and indeed it looks a bit different from that perspective. Still the only use case I see for freezing/sealing whole object (the way it works now) is when we expose some constant dictionary object on which each property counts, and that's very rare use case. I don't see much good in disallowing extensions to prototypes we expose. it's not JS way. We can prevent accidental modifications of *existing* API's but disallowing custom extensions is too restrictive and not friendly in my opinion. -- View this message in context: http://mozilla.6506.n7.nabble.com/A-case-for-removing-the-seal-freeze-isSealed-isFrozen-traps-tp272443p272674.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
I definitely agree that something like preventAccidentalExtensions (disallows new properties through [[Put]] but not [[DefineOwnProperty]]) has more common uses cases than preventExtensions, and for the precise reasons that David said. The security is against bugs usually, not attackers. PreventExtensions is a clumsy tool for managing capabilities because it leaves no room for giving *some* code permission while preventing other code, which is exactly what we want when the clueful *me* of now is writing code to manage the clueless *I* of the future. On Feb 15, 2013, at 6:31 AM, medikoo medikoo+mozilla@medikoo.com wrote: David, that's great clarification, and indeed it looks a bit different from that perspective. Still the only use case I see for freezing/sealing whole object (the way it works now) is when we expose some constant dictionary object on which each property counts, and that's very rare use case. I don't see much good in disallowing extensions to prototypes we expose. it's not JS way. We can prevent accidental modifications of *existing* API's but disallowing custom extensions is too restrictive and not friendly in my opinion. -- View this message in context: http://mozilla.6506.n7.nabble.com/A-case-for-removing-the-seal-freeze-isSealed-isFrozen-traps-tp272443p272674.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
... and security sensitive code could just ban/alter the reflection methods. On Feb 15, 2013 8:29 AM, Brandon Benvie bben...@mozilla.com wrote: I definitely agree that something like preventAccidentalExtensions (disallows new properties through [[Put]] but not [[DefineOwnProperty]]) has more common uses cases than preventExtensions, and for the precise reasons that David said. The security is against bugs usually, not attackers. PreventExtensions is a clumsy tool for managing capabilities because it leaves no room for giving *some* code permission while preventing other code, which is exactly what we want when the clueful *me* of now is writing code to manage the clueless *I* of the future. On Feb 15, 2013, at 6:31 AM, medikoo medikoo+mozilla@medikoo.com wrote: David, that's great clarification, and indeed it looks a bit different from that perspective. Still the only use case I see for freezing/sealing whole object (the way it works now) is when we expose some constant dictionary object on which each property counts, and that's very rare use case. I don't see much good in disallowing extensions to prototypes we expose. it's not JS way. We can prevent accidental modifications of *existing* API's but disallowing custom extensions is too restrictive and not friendly in my opinion. -- View this message in context: http://mozilla.6506.n7.nabble.com/A-case-for-removing-the-seal-freeze-isSealed-isFrozen-traps-tp272443p272674.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On Fri, Feb 15, 2013 at 9:24 AM, Erik Arvidsson erik.arvids...@gmail.comwrote: ... and security sensitive code could just ban/alter the reflection methods. On Feb 15, 2013 8:29 AM, Brandon Benvie bben...@mozilla.com wrote: I definitely agree that something like preventAccidentalExtensions (disallows new properties through [[Put]] but not [[DefineOwnProperty]]) has more common uses cases than preventExtensions, and for the precise reasons that David said. The security is against bugs usually, not attackers. PreventExtensions is a clumsy tool for managing capabilities because it leaves no room for giving *some* code permission while preventing other code, which is exactly what we want when the clueful *me* of now is writing code to manage the clueless *I* of the future. I think this would fit a really common use case, but I would say that the current attempted way to solve this problem is private names. Last I checked, private names (or the weak map variant) would not be frozen after an Object.freeze, but only trusted parties (like methods,getters/setters, and potentially those with the shared name) could modify it. The pattern I would like to see optimized for using Object.freeze is the functional approach. I think the tools are there. Object.freeze makes immutable objects, and using Object.create to use frozen objects as prototypes, and store just the differences in the child object could potentially be an elegant way of doing persistent data structures. I haven't really tested the performance of it now, but I wonder how optimized it could get. The prototype chains could get very deep, but seeing as they would all be frozen all the way up, I wonder if it could be made more efficient. - Russ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On 15 February 2013 14:29, Brandon Benvie bben...@mozilla.com wrote: I definitely agree that something like preventAccidentalExtensions (disallows new properties through [[Put]] but not [[DefineOwnProperty]]) has more common uses cases than preventExtensions, and for the precise reasons that David said. The security is against bugs usually, not attackers. PreventExtensions is a clumsy tool for managing capabilities because it leaves no room for giving *some* code permission while preventing other code, which is exactly what we want when the clueful *me* of now is writing code to manage the clueless *I* of the future. If you need private extensibility, just complement preventExtensions with installing a private map or expando object. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
2013/2/14 Allen Wirfs-Brock al...@wirfs-brock.com On Feb 13, 2013, at 12:53 PM, David Bruant wrote: Interesting. So what would happen when calling Object.isFrozen on a proxy? Would Object.isFrozen/isSealed/isExtensible reach out directly to the target? or a unique state trap returning a string for all of them? (state is too generic of a name, but you get the idea) This is a question regarding proxy design, rather than the MOP. Either get/setIntegrity traps to the handler or it forwards directly to the target. That's would be a design issue for Tom, but my starting point is to simply follow the current design decisions made for [[PreventExtensions]]/[[IsExtensible]] A get/setIntegrity trap with the invariant constraints of isExtensible/preventExtensions would be the obvious path to take. One thing that remains unclear to me: if the state of an object becomes explicit, we introduce the risk for this state to become inconsistent with the state from which it is derived. For example, setting the integrity of an object to frozen must still make all own properties non-configurable, i.e. Reflect.setIntegrity(obj, frozen) should have the same effect as Object.freeze(obj) Likewise, turning the last configurable property of a non-extensible object into a non-configurable property should automagically change the state to frozen, i.e. Object.defineProperty(obj, lastProperty, { configurable: false }) // must update internal state as well as the property Reflect.getIntegrity(obj) === frozen Will this not just shift the current complexity someplace else? Regardless on the final decision on (full) notification proxies, maybe these operations (isSealed/isFrozen) could have notification trap. The invariant is that the answer has to be the target one (all the time), so the trap return value is irrelevant. Like the getPrototypeOf trap. Right, one way or another these operations need to be part of the MOP. If we go for get/setIntegrity I wouldn't re-introduce all the derived operations as notification traps. Then we might as well leave things the way they are. Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On 13 February 2013 13:39, David Bruant bruan...@gmail.com wrote: Warning: In this post, I'll be diverging a bit from the main topic. Le 12/02/2013 14:29, Brendan Eich a écrit : Loss of identity, extra allocations, and forwarding overhead remain problems. I'm doubtful loss of identity matters often enough to be a valid argument here. I'd be interested in being proved wrong, though. I understand the point about extra allocation. I'll talk about that below. The forwarding overhead can be made inexistent in the very case I've exposed because in the handler, the traps you care about are absent from the handler, so engines are free to optimize the [[Get]]friends as operations applied directly to the target. You're being vastly over-optimistic about the performance and the amount of optimisation that can realistically be expected for proxies. Proxies are inherently unstructured, higher-order, and effectful, which defeats most sufficiently simple static analyses. A compiler has to work much, much harder to get useful results. Don't expect anything anytime soon. I've seen this in a previous experience on a Chrome extension where someone would seal an object as a form of documentation to express I need these properties to stay in the object. It looked like: function C(){ // play with |this| return Object.seal(this) } My point here is that people do want to protect their object integrity against untrusted parties which in that case was just people who'll contribute to this code in the future. Anecdotally, the person removed the Object.seal before the return because of performance reasons, based on a JSPerf test [3]. Interestingly, a JSPerf test with a proxy-based solution [4] might have convinced to do proxies instead of Object.seal. Take all these JSPerf micro benchmark games with two grains of salt; lots of them focus on premature optimisation. Also, seal and freeze are far more likely to see decent treat than proxies. But more importantly, I think you get too hung up on proxies as the proverbial hammer. Proxies are very much an expert feature. Using them for random micro abstractions is like shooting birds with a nuke. A language that makes that necessary would be a terrible language. All programmers messing with home-brewed proxies on a daily basis is a very scary vision, if you ask me. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Le 14/02/2013 18:11, Andreas Rossberg a écrit : On 13 February 2013 13:39, David Bruant bruan...@gmail.com wrote: Warning: In this post, I'll be diverging a bit from the main topic. Le 12/02/2013 14:29, Brendan Eich a écrit : Loss oread onlyf identity, extra allocations, and forwarding overhead remain problems. I'm doubtful loss of identity matters often enough to be a valid argument here. I'd be interested in being proved wrong, though. I understand the point about extra allocation. I'll talk about that below. The forwarding overhead can be made inexistent in the very case I've exposed because in the handler, the traps you care about are absent from the handler, so engines are free to optimize the [[Get]]friends as operations applied directly to the target. You're being vastly over-optimistic about the performance and the amount of optimisation that can realistically be expected for proxies. Proxies are inherently unstructured, higher-order, and effectful, which defeats most sufficiently simple static analyses. A compiler has to work much, much harder to get useful results. Don't expect anything anytime soon. var handler = {set: function(){throw new TypeError}} var p = new Proxy({a: 32}, handler); p.a; It's possible *at runtime* to notice that the handler of p doesn't have a get trap, optimize p.[[Get]] as target.[[Get]] and guard this optimization on handler modifications. Obviously, do that only if the code is hot. I feel it's not that much work than what JS engines do currently and the useful result is effectively getting rid of the forwarding overhead. Is this vastly over-optimistic? I've seen this in a previous experience on a Chrome extension where someone would seal an object as a form of documentation to express I need these properties to stay in the object. It looked like: function C(){ // play with |this| return Object.seal(this) } My point here is that people do want to protect their object integrity against untrusted parties which in that case was just people who'll contribute to this code in the future. Anecdotally, the person removed the Object.seal before the return because of performance reasons, based on a JSPerf test [3]. Interestingly, a JSPerf test with a proxy-based solution [4] might have convinced to do proxies instead of Object.seal. Take all these JSPerf micro benchmark games with two grains of salt; ... that's exactly what I said right after :-/ But that's a JSPerf test and it doesn't really measure the GC overhead of extra objects. JSPerf only measures one part of perf the story and its nice conclusion graph should be taken with a pinch of salt. lots of them focus on premature optimisation. I'm quite aware. I fear the Sphinx [1]. I wrote might have convinced to do proxies instead of Object.seal. I didn't say I agreed. and I actually don't. Also, seal and freeze are far more likely to see decent treat than proxies. Why so? But more importantly, I think you get too hung up on proxies as the proverbial hammer. Proxies are very much an expert feature. Using them for random micro abstractions is like shooting birds with a nuke. A language that makes that necessary would be a terrible language. All programmers messing with home-brewed proxies on a daily basis is a very scary vision, if you ask me. hmm... maybe. David [1] https://twitter.com/ubench_sphinx ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On 14 February 2013 19:16, David Bruant bruan...@gmail.com wrote: Le 14/02/2013 18:11, Andreas Rossberg a écrit : You're being vastly over-optimistic about the performance and the amount of optimisation that can realistically be expected for proxies. Proxies are inherently unstructured, higher-order, and effectful, which defeats most sufficiently simple static analyses. A compiler has to work much, much harder to get useful results. Don't expect anything anytime soon. var handler = {set: function(){throw new TypeError}} var p = new Proxy({a: 32}, handler); p.a; It's possible *at runtime* to notice that the handler of p doesn't have a get trap, optimize p.[[Get]] as target.[[Get]] and guard this optimization on handler modifications. Obviously, do that only if the code is hot. I feel it's not that much work than what JS engines do currently and the useful result is effectively getting rid of the forwarding overhead. Is this vastly over-optimistic? Yes. Proxies hook into many different basic operations, and there are many special cases you could potentially optimise for each of them, many of which don't come for free. I very much doubt that any vendor currently has serious plans to go down that rathole instead of spending their energy elsewhere. Certainly not before it is clear how (and how much) proxies will actually be used in practice. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On 14 February 2013 01:05, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Where do without, means replaced with set/getIntegrity traps and objects have explicit internal state whose value is one of normal/non-extensible/sealed/frozen (and possibly) fixed-inheritance between normal and non-extensible to freeze [[Prototype]]). [[SetIntegrity]] can increase the integrity level but not decrease it. The perf and invariant complexity concerns come from the fact that the sealed/frozen status of an object can only be inferred by inspecting all of its methods. Having an explicit state eliminates the need to do this inspection. It also simplifies the MOP by merging all of the extensible/sealed/frozen related MOP operations into only two ops. But, one way or another, these object state transitions must be accounted for in the MOP. For this to fly, implementation have to be able to expand their current 1 bit of of extensible state to at least 2 bits (3 would be better). Or perhaps not, I suppose we could just introduce the MOP level changes and a lazy implementation could continue to infer the state by examining all its methods. I still must be missing something. Why should the language be changed when the proposed change is equivalent anyway? Why is this an optimisation that the spec should worry about instead of the implementations? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Andreas Rossberg wrote: But more importantly, I think you get too hung up on proxies as the proverbial hammer. Proxies are very much an expert feature. Using them for random micro abstractions is like shooting birds with a nuke. A language that makes that necessary would be a terrible language. All programmers messing with home-brewed proxies on a daily basis is a very scary vision, if you ask me. This. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Andreas Rossberg wrote: On 14 February 2013 19:16, David Bruantbruan...@gmail.com wrote: Le 14/02/2013 18:11, Andreas Rossberg a écrit : You're being vastly over-optimistic about the performance and the amount of optimisation that can realistically be expected for proxies. Proxies are inherently unstructured, higher-order, and effectful, which defeats most sufficiently simple static analyses. A compiler has to work much, much harder to get useful results. Don't expect anything anytime soon. var handler = {set: function(){throw new TypeError}} var p = new Proxy({a: 32}, handler); p.a; It's possible *at runtime* to notice that the handler of p doesn't have a get trap, optimize p.[[Get]] as target.[[Get]] and guard this optimization on handler modifications. Obviously, do that only if the code is hot. I feel it's not that much work than what JS engines do currently and the useful result is effectively getting rid of the forwarding overhead. Is this vastly over-optimistic? Yes. Proxies hook into many different basic operations, and there are many special cases you could potentially optimise for each of them, many of which don't come for free. I very much doubt that any vendor currently has serious plans to go down that rathole instead of spending their energy elsewhere. Certainly not before it is clear how (and how much) proxies will actually be used in practice. You're right in general, and we have not optimized, e.g. inlining scripted trap calls. We did do something special for our new DOM bindings I wanted to pass along, in case anyone is interested: https://bugzilla.mozilla.org/show_bug.cgi?id=769911 Thanks to bz for the link. This is yet another inline cache specialization for expandos on nodelists. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Warning: In this post, I'll be diverging a bit from the main topic. Le 12/02/2013 14:29, Brendan Eich a écrit : Loss of identity, extra allocations, and forwarding overhead remain problems. I'm doubtful loss of identity matters often enough to be a valid argument here. I'd be interested in being proved wrong, though. I understand the point about extra allocation. I'll talk about that below. The forwarding overhead can be made inexistent in the very case I've exposed because in the handler, the traps you care about are absent from the handler, so engines are free to optimize the [[Get]]friends as operations applied directly to the target. A handler-wise write barrier can deoptimize but in most practical cases, the deoptimization won't happen because in most practical cases handlers don't change. It seems to me that you are focusing too much on share ... to untrusted parties. Your very own recent words [1]: In a programming-in-the-large setting, a writable data property is inviting Murphy's Law. I'm not talking about security in a mixed-trust environment specifically. Large programs become mixed trust, even when it's just me, myself, and I (over time) hacking the large amount of code. ...to which I agree with (obviously?) And Be a better language for writing complex applications is in the first goals [2] Maybe I should use another word than untrusted parties. What I mean is any code that will manipulate something without necessarily caring to learn about what this something expects as precondition and own invariants. This includes security issues of course, but also buggy code (which, in big applications, are often related to mismatch between a precondition/expectation and how something is used). I've seen this in a previous experience on a Chrome extension where someone would seal an object as a form of documentation to express I need these properties to stay in the object. It looked like: function C(){ // play with |this| return Object.seal(this) } My point here is that people do want to protect their object integrity against untrusted parties which in that case was just people who'll contribute to this code in the future. Anecdotally, the person removed the Object.seal before the return because of performance reasons, based on a JSPerf test [3]. Interestingly, a JSPerf test with a proxy-based solution [4] might have convinced to do proxies instead of Object.seal. But that's a JSPerf test and it doesn't really measure the GC overhead of extra objects. Are there data on this? Are there methodologies to measure this overhead? I understand it, but I find myself unable to pull up numbers on this topic and convincing arguments that JSPerf only measures one part of perf the story and its nice conclusion graph should be taken with a pinch of salt. It's true you want either a membrane or an already-frozen object in such a setting. Not a membrane, just a proxy that protects its target. Objects linked from the proxy likely came from somewhere else. They're in charge of deciding of their own integrity policy. And outside of untrusted parties, frozen objects have their uses -- arguably more over time with safe parallelism in JS. Arguably indeed. I would love to see this happen. Still, if (deeply) frozen POJSO could be part shared among contexts, I think we can agree that it wouldn't apply to frozen proxies for a long time (ever?) I went a bit too far suggesting frozen objects could de-facto disappear with proxies. I'm still unclear on the need for specific seal/freeze/isSealed/isFrozen traps David [1] https://mail.mozilla.org/pipermail/es-discuss/2013-February/028724.html [2] http://wiki.ecmascript.org/doku.php?id=harmony:harmony#goals [3] jsperf.com/object-seal-freeze/ [4] http://jsperf.com/object-seal-freeze/2 /be David Bruant wrote: Hi, The main use case (correct me if I'm wrong) for freezing/sealing an object is sharing an object to untrusted parties while preserving the object integrity. There is also the tamper-proofing of objects everyone has access to (Object.prototype in the browser) In a world with proxies, it's easy to build new objects with high integrity without Object.freeze: build your object, share only a wrapped version to untrusted parties, the handler takes care of the integrity. function thrower(){ throw new Error('nope'); } var frozenHandler = { set: thrower, defineProperty: thrower, delete: thrower }; function makeFrozen(o){ return new Proxy(o, frozenHandler); } This is true to a point that I wonder why anyone would call Object.freeze on script-created objects any longer... By design and for good reasons, proxies are a subset of script-created objects, so my previous sentence contained: I wonder why anyone would call Object.freeze on proxies... There were concerned about Object.freeze/seal being costly on proxies if
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Hi David, 2013/2/13 David Bruant bruan...@gmail.com Le 12/02/2013 14:29, Brendan Eich a écrit : Loss of identity, extra allocations, and forwarding overhead remain problems. I'm doubtful loss of identity matters often enough to be a valid argument here. I'd be interested in being proved wrong, though. I do think identity is an issue in practice, especially without a membrane in-place to preserve object identity across the membrane. Also: It's true you want either a membrane or an already-frozen object in such a setting. Not a membrane, just a proxy that protects its target. Objects linked from the proxy likely came from somewhere else. They're in charge of deciding of their own integrity policy. Freezing an object by handing out a read-only view is fragile without a full membrane: what if a method of the wrapped object returns |this|, or passes its |this| argument to some client-provided callback? It's all too easy for a direct reference to the target to escape, thus bypassing the read-only view. This is not the case with frozen objects. I went a bit too far suggesting frozen objects could de-facto disappear with proxies. I'm still unclear on the need for specific seal/freeze/isSealed/isFrozen traps I think Allen and I reached consensus that we might do without those traps. In addition, Allen was considering an alternative design where the state of an object (i.e. extensible, non-extensible, sealed or frozen) is represented explicitly as an internal property, so that Object.isFrozen and Object.isSealed must not derive the state of an object from its properties. Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Le 13/02/2013 20:36, Tom Van Cutsem a écrit : Hi David, I went a bit too far suggesting frozen objects could de-facto disappear with proxies. I'm still unclear on the need for specific seal/freeze/isSealed/isFrozen traps I think Allen and I reached consensus that we might do without those traps. Excellent! In addition, Allen was considering an alternative design where the state of an object (i.e. extensible, non-extensible, sealed or frozen) is represented explicitly as an internal property, so that Object.isFrozen and Object.isSealed must not derive the state of an object from its properties. Interesting. So what would happen when calling Object.isFrozen on a proxy? Would Object.isFrozen/isSealed/isExtensible reach out directly to the target? or a unique state trap returning a string for all of them? (state is too generic of a name, but you get the idea) Regardless on the final decision on (full) notification proxies, maybe these operations (isSealed/isFrozen) could have notification trap. The invariant is that the answer has to be the target one (all the time), so the trap return value is irrelevant. Like the getPrototypeOf trap. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
On Feb 13, 2013, at 12:53 PM, David Bruant wrote: Le 13/02/2013 20:36, Tom Van Cutsem a écrit : Hi David, I went a bit too far suggesting frozen objects could de-facto disappear with proxies. I'm still unclear on the need for specific seal/freeze/isSealed/isFrozen traps I think Allen and I reached consensus that we might do without those traps. Excellent! Where do without, means replaced with set/getIntegrity traps and objects have explicit internal state whose value is one of normal/non-extensible/sealed/frozen (and possibly) fixed-inheritance between normal and non-extensible to freeze [[Prototype]]). [[SetIntegrity]] can increase the integrity level but not decrease it. The perf and invariant complexity concerns come from the fact that the sealed/frozen status of an object can only be inferred by inspecting all of its methods. Having an explicit state eliminates the need to do this inspection. It also simplifies the MOP by merging all of the extensible/sealed/frozen related MOP operations into only two ops. But, one way or another, these object state transitions must be accounted for in the MOP. For this to fly, implementation have to be able to expand their current 1 bit of of extensible state to at least 2 bits (3 would be better). Or perhaps not, I suppose we could just introduce the MOP level changes and a lazy implementation could continue to infer the state by examining all its methods. In addition, Allen was considering an alternative design where the state of an object (i.e. extensible, non-extensible, sealed or frozen) is represented explicitly as an internal property, so that Object.isFrozen and Object.isSealed must not derive the state of an object from its properties. Interesting. So what would happen when calling Object.isFrozen on a proxy? Would Object.isFrozen/isSealed/isExtensible reach out directly to the target? or a unique state trap returning a string for all of them? (state is too generic of a name, but you get the idea) This is a question regarding proxy design, rather than the MOP. Either get/setIntegrity traps to the handler or it forwards directly to the target. That's would be a design issue for Tom, but my starting point is to simply follow the current design decisions made for [[PreventExtensions]]/[[IsExtensible]] Regardless on the final decision on (full) notification proxies, maybe these operations (isSealed/isFrozen) could have notification trap. The invariant is that the answer has to be the target one (all the time), so the trap return value is irrelevant. Like the getPrototypeOf trap. Right, one way or another these operations need to be part of the MOP. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
A case for removing the seal/freeze/isSealed/isFrozen traps
Hi, The main use case (correct me if I'm wrong) for freezing/sealing an object is sharing an object to untrusted parties while preserving the object integrity. There is also the tamper-proofing of objects everyone has access to (Object.prototype in the browser) In a world with proxies, it's easy to build new objects with high integrity without Object.freeze: build your object, share only a wrapped version to untrusted parties, the handler takes care of the integrity. function thrower(){ throw new Error('nope'); } var frozenHandler = { set: thrower, defineProperty: thrower, delete: thrower }; function makeFrozen(o){ return new Proxy(o, frozenHandler); } This is true to a point that I wonder why anyone would call Object.freeze on script-created objects any longer... By design and for good reasons, proxies are a subset of script-created objects, so my previous sentence contained: I wonder why anyone would call Object.freeze on proxies... There were concerned about Object.freeze/seal being costly on proxies if defined as preventExtension + enumerate + nbProps*defineProperty. Assuming Object.freeze becomes de-facto deprecated in favor of proxy-wrapping for high-integrity use cases, maybe that cost is not that big of a deal. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A case for removing the seal/freeze/isSealed/isFrozen traps
Loss of identity, extra allocations, and forwarding overhead remain problems. It seems to me that you are focusing too much on share ... to untrusted parties. It's true you want either a membrane or an already-frozen object in such a setting. But the latter case, already-frozen object, does not want a membrane, both to avoid identity change and to avoid the allocation and forwarding overheads. And outside of untrusted parties, frozen objects have their uses -- arguably more over time with safe parallelism in JS. /be David Bruant wrote: Hi, The main use case (correct me if I'm wrong) for freezing/sealing an object is sharing an object to untrusted parties while preserving the object integrity. There is also the tamper-proofing of objects everyone has access to (Object.prototype in the browser) In a world with proxies, it's easy to build new objects with high integrity without Object.freeze: build your object, share only a wrapped version to untrusted parties, the handler takes care of the integrity. function thrower(){ throw new Error('nope'); } var frozenHandler = { set: thrower, defineProperty: thrower, delete: thrower }; function makeFrozen(o){ return new Proxy(o, frozenHandler); } This is true to a point that I wonder why anyone would call Object.freeze on script-created objects any longer... By design and for good reasons, proxies are a subset of script-created objects, so my previous sentence contained: I wonder why anyone would call Object.freeze on proxies... There were concerned about Object.freeze/seal being costly on proxies if defined as preventExtension + enumerate + nbProps*defineProperty. Assuming Object.freeze becomes de-facto deprecated in favor of proxy-wrapping for high-integrity use cases, maybe that cost is not that big of a deal. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss