Reflection of global bindings
On 12/15/12 12:21 PM, David Bruant wrote:
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
No, nothing of the sort. The example shows it present on the global (the third alert in my example) but missing from the WindowProxy (fourth alert).
The need to do what was proposed is the same though. Configurability can be arm twisted into submission for things like document and location via accessors, and the WindowProxy can refuse to accept non-configurable properties defined using Object.defineProperty, but that leaves non-configurable bindings created during Top Level Declaration Instantiation that need to be dealt with.
Le 15/12/2012 18:23, Boris Zbarsky a écrit :
On 12/15/12 12:21 PM, David Bruant wrote:
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
No, nothing of the sort. The example shows it present on the global (the third alert in my example) but missing from the WindowProxy (fourth alert).
I'm comparing the second and fourth alert (that's not what the example was created to show, but that's what it shows too). In the second alert, there is the 'foo' property and it is non-configurable as per the spec, because you var-declared it. In the 4th alert, the property has magically disappeared.
On 12/15/12 12:34 PM, David Bruant wrote:
No, nothing of the sort. The example shows it present on the global (the third alert in my example) but missing from the WindowProxy (fourth alert). I'm comparing the second and fourth alert (that's not what the example was created to show, but that's what it shows too). In the second alert, there is the 'foo' property and it is non-configurable as per the spec, because you var-declared it. In the 4th alert, the property has magically disappeared.
Sure, but those aren't properties on the global. They're properties on a different object.
I agree there's a problem in terms of what getOwnPropertyDescriptor returns for the property at the time of alert #2. Just want to make sure we have the problem statement straight. ;)
Le 15/12/2012 18:37, Boris Zbarsky a écrit :
On 12/15/12 12:34 PM, David Bruant wrote:
No, nothing of the sort. The example shows it present on the global (the third alert in my example) but missing from the WindowProxy (fourth alert). I'm comparing the second and fourth alert (that's not what the example was created to show, but that's what it shows too). In the second alert, there is the 'foo' property and it is non-configurable as per the spec, because you var-declared it. In the 4th alert, the property has magically disappeared.
Sure, but those aren't properties on the global. They're properties on a different object.
Script authors can't observe the fact that it's a different object. They just have access to one WindowProxy object (they know it's the same with object identity). This object is the one that must show some consistency.
I agree there's a problem in terms of what getOwnPropertyDescriptor returns for the property at the time of alert #2. Just want to make sure we have the problem statement straight. ;)
Sounds good :-) These problems are subtle; I appreciate the help in expressing them accurately.
Thanks,
On 12/15/12 12:48 PM, David Bruant wrote:
Sure, but those aren't properties on the global. They're properties on a different object. Script authors can't observe the fact that it's a different object.
Yes, they can. The third and fourth alerts in my testcase constitute just such an observation: per spec the third alert there must be looking at a property of the global, and it is, while the fourth alert is clearly looking at some other object, since it has a different value for the property.
There's a slight wrench in here in that the script-visible "this" object for non-strict functions is also supposed to be the global per spec, but in practice it's the WindowProxy.
They just have access to one WindowProxy object (they know it's the same with object identity).
They have direct access to just the WindowProxy. They have access to property gets and sets on the actual global, though, via barewords.
This object is the one that must show some consistency.
That, we agree on.
On Dec 15, 2012, at 9:21 AM, David Bruant wrote:
Hi,
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
The careful ECMAScript 5.1 reader knows that global var-defined variables are supposed to be reflected as own non-configurable properties of the global object. Reflecting the property as such commits the object to keep the property forever which, as we've seen in Boris example, is not compatible with how the web works.
I don't think it'll be possible to change how global objects in same-origin iframes work nor relax ES5 invariants; so my proposal is to have var/let/const/function global declarations reflected as configurable, but acting as if they were not. This would also require a couple of changes in the spec and consequently JS engines and certainly test262. Other proposals welcome, of course.
Note that in ES6 global bindings introduced by let/const/class/import bound using a declarative environment record and will not be reflected at all on the global object.
That still leaves any issues relating to var and function declarations.
Allen Wirfs-Brock wrote:
On Dec 15, 2012, at 9:21 AM, David Bruant wrote:
Hi,
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
The careful ECMAScript 5.1 reader knows that global var-defined variables are supposed to be reflected as own non-configurable properties of the global object. Reflecting the property as such commits the object to keep the property forever which, as we've seen in Boris example, is not compatible with how the web works.
I don't think it'll be possible to change how global objects in same-origin iframes work nor relax ES5 invariants; so my proposal is to have var/let/const/function global declarations reflected as configurable, but acting as if they were not. This would also require a couple of changes in the spec and consequently JS engines and certainly test262. Other proposals welcome, of course.
Note that in ES6 global bindings introduced by let/const/class/import bound using a declarative environment record and will not be reflected at all on the global object.
That still leaves any issues relating to var and function declarations.
Reflecting var and function bindings on window (or |this| or |self| or other aliases) as configurable properties, but refusing to allow reconfiguration, is a solution, however distasteful. Allowing configuration is no good, of course.
From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Saturday, December 15, 2012 14:26
Reflecting var and function bindings on window (or |this| or |self| or other aliases) as configurable properties, but refusing to allow reconfiguration, is a solution, however distasteful. Allowing configuration is no good, of course.
As someone who's trying desperately to follow along with all these subtle issues from the sidelines... Why is allowing configuration of such properties no good?
Domenic Denicola wrote:
From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Saturday, December 15, 2012 14:26
Reflecting var and function bindings on window (or |this| or |self| or other aliases) as configurable properties, but refusing to allow reconfiguration, is a solution, however distasteful. Allowing configuration is no good, of course.
As someone who's trying desperately to follow along with all these subtle issues from the sidelines... Why is allowing configuration of such properties no good?
Becausethe only integrity guarantee in JS prior to ES5 was via var and function making non-configurable bindings. This is used especially in closures, e.g. You can't delete a var- or function-induced binding not created from eval. But it is also used at the top-level, not only by code but also by VMs that can optimize accordingly (no delete, the "slot" can't change).
It may seem silly to reflect the global bindings as configurable but refuse configuration attempts, but that satisfies the invariant at stake. Reflecting the function and var bindings non-configurable but allowing apparent reconfiguration via WindowProxy-forwarded navigation breaks the invariant.
Le 15/12/2012 19:38, Allen Wirfs-Brock a écrit :
On Dec 15, 2012, at 9:21 AM, David Bruant wrote:
Hi,
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
The careful ECMAScript 5.1 reader knows that global var-defined variables are supposed to be reflected as own non-configurable properties of the global object. Reflecting the property as such commits the object to keep the property forever which, as we've seen in Boris example, is not compatible with how the web works.
I don't think it'll be possible to change how global objects in same-origin iframes work nor relax ES5 invariants; so my proposal is to have var/let/const/function global declarations reflected as configurable, but acting as if they were not. This would also require a couple of changes in the spec and consequently JS engines and certainly test262. Other proposals welcome, of course. Note that in ES6 global bindings introduced by let/const/class/import bound using a declarative environment record and will not be reflected at all on the global object.
Thanks for the precision. I take back what I said about "var/let/const/function" and reduce it to "var/function".
On Dec 15, 2012, at 12:12 PM, Brendan Eich wrote:
Domenic Denicola wrote:
From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Saturday, December 15, 2012 14:26
Reflecting var and function bindings on window (or |this| or |self| or other aliases) as configurable properties, but refusing to allow reconfiguration, is a solution, however distasteful. Allowing configuration is no good, of course.
As someone who's trying desperately to follow along with all these subtle issues from the sidelines... Why is allowing configuration of such properties no good?
Becausethe only integrity guarantee in JS prior to ES5 was via var and function making non-configurable bindings. This is used especially in closures, e.g. You can't delete a var- or function-induced binding not created from eval. But it is also used at the top-level, not only by code but also by VMs that can optimize accordingly (no delete, the "slot" can't change).
It may seem silly to reflect the global bindings as configurable but refuse configuration attempts, but that satisfies the invariant at stake. Reflecting the function and var bindings non-configurable but allowing apparent reconfiguration via WindowProxy-forwarded navigation breaks the invariant.
Property attributes were originally a specification device (that may have also existed in implementation) that were used to describe the semantics of certain ES operations. Originally there was no direct way for ES code to set or inspect (except for DontEnum) the state of attributes. For example, certain properties were specified to have a DontDelete attribute and the delete operator was specified to never delete such properties. There was no way for ES code to give an arbitrary attribute a DontDelete attribute. There was no specified guarantee that a property with that attribute wouldn't disappear (except not via the delete operator) and no specified guarantee that a property with a DontDelete attribute would always continue to have the attribute. In fact, the ES3 spec. explicitly said that the internal methods such as [[Delete]] for "host objects" could be "implemented in any manner (implicitly this would include disregarding attributes) and even gives an example of the internal methods of a host object producing inconsistent results. This is the world in which WindowProxy and other DOM behaviors originally evolved.
In ES5, we added reflection operations that allow ES code to inspect and modify the attributes of any property of any object. We also reinterpreted DontDelete as [[Configurarable]]:false. In the early drafts of what became ES5, that was all we did. The attributes still were used to describe the semantics. of various ES operations. In ES5, that set of operations expanded to include the reflection operations for modifying attributes. For example, [[Configurable]]: false prevented the Object.defineProperty operation from being used to change the attribute values of a property. However, that was as far as the original ES5 draft changes went. Host objects (and ES extensions) were still allowed to do pretty much anything they wanted.
Fairly late in the development of ES5 (by my recollection) MarkM championed the position that the property attribute values exposed via Object.getOwnPropertyDescritor were more than just specification control points. His position was that they exposed certain absolute invariants to which all objects, including host objets, must conform. This led to a small set of invariants being include in section 8.6.2 of ES5. This included the invariant that if a property can observably disappear, its [[Configurable]] internal property must observably have a value of true. MarkM also consistently emphasized that the required invariants did not imply that their converse was also an invariant. For example, the fact that a property was observably configurable did not imply that the delete operation could actually be used to remove that property from its object.
We added something and lost some by introducing those invariants. We added some certainty about whether a few specific kinds of observable state transitions are allowed or not. However, in the spec. we have essentially lost the ability to use the attribute values as control points for some of the specification algorithms. For example, if a property may be non-deletable, even though its [[Configurable]] attribute is true, then the delete operation can't use the value of the [[Configurable]] attribute to determine whether or not it is allowed to actually remove the property and whether it should return true or false as its result.
So, to me, it sounds like that to continue down this path we should really add new non-reflected properties attributes that are the real control points for the ES semantics. Eg, we may need [[RealReadOnly]], [[RealDeletable]], and [[RealReconfigurable]] attributes to describe all the states and state transitions that are actually exist within the legacy DOM (and the pure ES global declaration semantics). As these attributes would not be reflected by Object.getOwnPropertyDescriptor/Object.defineProperty they would have to set in some other internal manner when object instances are created. Tis also means that Proxy based object implementations would also need to have some mechanism for emulating these "Real" attributes.
So, it feels to me like we are circling about to the a place similar to where we were prior to ES5. We need specification/implementation layer control points (ie, hidden attributes) that are not directly observable or controllable by ES code (except for Proxy handlers). Plus now we also have a set of different reflectable attributes that have some non-obvious relationship to those hidden attributes. I'm not sure that this is actual progress.
I don't think we're circling. I think we're doing a spiral (which may give the impression that we're circling while we're moving forward).
More answers inline.
Le 15/12/2012 22:52, Allen Wirfs-Brock a écrit :
(...)
In ES5, we added reflection operations that allow ES code to inspect and modify the attributes of any property of any object. We also reinterpreted DontDelete as [[Configurarable]]:false. In the early drafts of what became ES5, that was all we did. The attributes still were used to describe the semantics. of various ES operations. In ES5, that set of operations expanded to include the reflection operations for modifying attributes. For example, [[Configurable]]: false prevented the Object.defineProperty operation from being used to change the attribute values of a property. However, that was as far as the original ES5 draft changes went. Host objects (and ES extensions) were still allowed to do pretty much anything they wanted.
I wish to note here that to some extent, it makes Table 5 and 6 of 8.6.1 not-that-normative since they only describe the semantics of ECMAScript spec objects, not host objects. For instance, host objects aren't required to anything regarding "enumerable". Since host objects are given all freedom, property descriptor attributes do not have a semantics. The semantic is only provided by the algorithms (8.12, 15.4.5.1, etc. or the host object semantics, etc.) manipulating these attributes. The invariants of the ES5 algorithms can be documented to make them more easily understandable, but it doesn't make them invariants for any object because host objects are free to have any semantics.
As soon as ES5 decided that host objects had all freedom, it withdrew its own right to define a specific semantics for attributes. ES5 still defines the semantics for its own objects through the algorithms, but withdrew its right to say "when you meet such attribute with such value on any object, then, you know X, Y, Z"
Fairly late in the development of ES5 (by my recollection) MarkM championed the position that the property attribute values exposed via Object.getOwnPropertyDescritor were more than just specification control points. His position was that they exposed certain absolute invariants to which all objects, including host objets, must conform. This led to a small set of invariants being include in section 8.6.2 of ES5. This included the invariant that if a property can observably disappear, its [[Configurable]] internal property must observably have a value of true. MarkM also consistently emphasized that the required invariants did not imply that their converse was also an invariant. For example, the fact that a property was observably configurable did not imply that the delete operation could actually be used to remove that property from its object.
ES5 withdrew its own right to define the full semantics of attributes, but defensive programming can't work with no semantics. Invariants are the bare minimum to be expected from any object. I'd like to point out that the door might be open to add new semantics here.
We added something and lost some by introducing those invariants. We added some certainty about whether a few specific kinds of observable state transitions are allowed or not. However, in the spec. we have essentially lost the ability to use the attribute values as control points for some of the specification algorithms. For example, if a property may be non-deletable, even though its [[Configurable]] attribute is true, then the delete operation can't use the value of the [[Configurable]] attribute to determine whether or not it is allowed to actually remove the property and whether it should return true or false as its result.
The ES5 spec does use attributes as control points, so it wasn't fully lost.
So, to me, it sounds like that to continue down this path we should really add new non-reflected properties attributes that are the real control points for the ES semantics. Eg, we may need [[RealReadOnly]], [[RealDeletable]], and [[RealReconfigurable]] attributes to describe all the states and state transitions that are actually exist within the legacy DOM (and the pure ES global declaration semantics).
I agree with this analysis.
As these attributes would not be reflected by Object.getOwnPropertyDescriptor/Object.defineProperty they would have to set in some other internal manner when object instances are created.
I may disagree here. Although ES5 has lost its right to define what attributes exactly mean (beyond the invariants), it may make sense for each object to communicate its state via custom attributes. In a way, enumerable can be considered as such an attribute. It has exactly zero official semantics for host objects, but per spec, if you create your own object with {} or [], and play with enumerable and configurable, you know exactly what to expect. Because host objects can do anything, the semantics to expect from any object is limited to invariants. However, for spec objects, there are strong expectations that can be expected from using Object.getOwnPropertyDescriptor/Object.defineProperty. Creating new attributes may be a way for some objects acquired in predefined conditions to communicate their intent.
If ECMAScript can't dictate what each attribute exactly mean, it still has a role to play to create conventions (like with "enumerable" and it worked). ES5 paved the cowpath for existing spec objects, defined the bare minimum of semantics to expect from all objects and created the "enumerable" convention. Maybe it's time to explore how different objects can express their own semantics (in cases where it can be useful).
Tis also means that Proxy based object implementations would also need to have some mechanism for emulating these "Real" attributes.
Being able to express any behavior using an independent function for each trap is more than enough power I think.
So, it feels to me like we are circling about to the a place similar to where we were prior to ES5.
Now, we have a way for objects to describe a couple of properties (non-deletable, constant property, non-extensible) and assuming they follow conventions, to say whether a given property is enumerable. That's better than prior ES5.
We need specification/implementation layer control points (ie, hidden attributes) that are not directly observable or controllable by ES code (except for Proxy handlers).
That's a necessary consequence of host objects being allowed to do whatever they want.
Plus now we also have a set of different reflectable attributes that have some non-obvious relationship to those hidden attributes. I'm not sure that this is actual progress.
I think that is progress, but the road hadn't been fully traversed yet. Using only a couple of reflectable attributes to fully represent the internal state of objects was a fantasy. One I wish was realistic too, but clearly isn't with what WindowProxy constraints to.
The way forward from ES3 to ES5 was to expose some internal properties to be able to understand how any object works internally (+ the "enumerable" convention). The way forward is probably to add more finer-grained attributes that work only on some objects, but are irrelevant to others, create other conventions.
On 15 December 2012 22:52, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
So, to me, it sounds like that to continue down this path we should really add new non-reflected properties attributes that are the real control points for the ES semantics. Eg, we may need [[RealReadOnly]], [[RealDeletable]], and [[RealReconfigurable]] attributes to describe all the states and state transitions that are actually exist within the legacy DOM (and the pure ES global declaration semantics). As these attributes would not be reflected by Object.getOwnPropertyDescriptor/Object.defineProperty they would have to set in some other internal manner when object instances are created. Tis also means that Proxy based object implementations would also need to have some mechanism for emulating these "Real" attributes.
Now I'm really scared. Please let's not go there.
I see the following preferable solutions to deal with DOM features violating ES:
-
Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
-
Where we can't (sadly, probably most cases), and are forced to codify existing DOM hacks in ES, isolate these hacks as much as possible. Specifically, in the current case, define them as specifics of the global object (the global object is a lost cause anyway).
On Mon, Dec 17, 2012 at 2:03 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 15 December 2012 22:52, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
So, to me, it sounds like that to continue down this path we should really add new non-reflected properties attributes that are the real control points for the ES semantics. Eg, we may need [[RealReadOnly]], [[RealDeletable]], and [[RealReconfigurable]] attributes to describe all the states and state transitions that are actually exist within the legacy DOM (and the pure ES global declaration semantics). As these attributes would not be reflected by Object.getOwnPropertyDescriptor/Object.defineProperty they would have to set in some other internal manner when object instances are created. Tis also means that Proxy based object implementations would also need to have some mechanism for emulating these "Real" attributes.
Now I'm really scared. Please let's not go there.
I see the following preferable solutions to deal with DOM features violating ES:
Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
Where we can't (sadly, probably most cases), and are forced to codify existing DOM hacks in ES, isolate these hacks as much as possible. Specifically, in the current case, define them as specifics of the global object (the global object is a lost cause anyway).
In general, I might be fine with that approach. But because of direct proxies, it doesn't work for invariant enforcement. Direct proxies can use the presence of a single invariant-violating object to create any number of other invariant-violating objects.
On 17 December 2012 13:01, Mark S. Miller <erights at google.com> wrote:
On Mon, Dec 17, 2012 at 2:03 AM, Andreas Rossberg <rossberg at google.com> wrote:
I see the following preferable solutions to deal with DOM features violating ES:
Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
Where we can't (sadly, probably most cases), and are forced to codify existing DOM hacks in ES, isolate these hacks as much as possible. Specifically, in the current case, define them as specifics of the global object (the global object is a lost cause anyway).
In general, I might be fine with that approach. But because of direct proxies, it doesn't work for invariant enforcement. Direct proxies can use the presence of a single invariant-violating object to create any number of other invariant-violating objects.
Yes, but is that a different problem than the global object itself? Why would you expect anything else? And how would introducing an extra set of internal attributes help?
Of course, I personally wouldn't mind being radical and simply forbid proxying the global object altogether. But I assume that you are going to say that there are important use cases. :)
On Mon, Dec 17, 2012 at 4:26 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 17 December 2012 13:01, Mark S. Miller <erights at google.com> wrote:
On Mon, Dec 17, 2012 at 2:03 AM, Andreas Rossberg <rossberg at google.com> wrote:
I see the following preferable solutions to deal with DOM features violating ES:
Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
Where we can't (sadly, probably most cases), and are forced to codify existing DOM hacks in ES, isolate these hacks as much as possible. Specifically, in the current case, define them as specifics of the global object (the global object is a lost cause anyway).
In general, I might be fine with that approach. But because of direct proxies, it doesn't work for invariant enforcement. Direct proxies can use the presence of a single invariant-violating object to create any number of other invariant-violating objects.
Yes, but is that a different problem than the global object itself? Why would you expect anything else? And how would introducing an extra set of internal attributes help?
Sorry, too much context. I agree about not specifying a new set of internal attributes. I only mean that the WindowProxy must be specified (on the HTML side) so that it doesn't violate these invariants. Regarding the need for these properties to refuse being configured, that seems adequately handled with prose in both ES and HTML, without needing to introduce formal new internal attributes. The ES spec could be silent (with a note) on whether these properties are reported as non-configurable, so that non-browser environments without a WindowProxy don't need to reproduce this insanity.
The sanity check everyone should continue to use is whether the WindowProxy behavior could be self-hosted using direct proxies. In this case, the WindowProxy would need to use the shadow proxy technique. The real target is the hidden window, and the shadow target (the one the proxy itself knows directly) has no non-configurable properties. The handler refuses to configure any property that is non-configurable on the real target, while continuing to report all these properties as configurable.
An easier solution that would be fine with me is for these "var" and "function" variables to actually be configurable, so that we don't need this odd behavior at all. Brendan is right that this is a breaking change. But is it an important one? I don't know. But it doesn't hurt any integrity issue I care about.
Of course, I personally wouldn't mind being radical and simply forbid proxying the global object altogether. But I assume that you are going to say that there are important use cases. :)
Independent of these specific issues, I think that the whole Window vs WindowProxy hack is terrible. If anyone thinks there is any hope of getting rid of this hack, I encourage you to try.
On Mon, Dec 17, 2012 at 5:03 AM, Andreas Rossberg <rossberg at google.com>wrote:
Now I'm really scared. Please let's not go there.
I see the following preferable solutions to deal with DOM features violating ES:
- Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
Thank you. I had a draft response that said something similar, citing WebIDL's "Window.prototype" issue[0], but this is to the point.
Rick
Le 17/12/2012 13:51, Mark S. Miller a écrit :
On Mon, Dec 17, 2012 at 4:26 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 17 December 2012 13:01, Mark S. Miller <erights at google.com> wrote:
On Mon, Dec 17, 2012 at 2:03 AM, Andreas Rossberg <rossberg at google.com> wrote:
I see the following preferable solutions to deal with DOM features violating ES:
Lobby to fix the DOM and make it conform to ES instead of the other way round. Alex Russell has argued for this repeatedly.
Where we can't (sadly, probably most cases), and are forced to codify existing DOM hacks in ES, isolate these hacks as much as possible. Specifically, in the current case, define them as specifics of the global object (the global object is a lost cause anyway). In general, I might be fine with that approach. But because of direct proxies, it doesn't work for invariant enforcement. Direct proxies can use the presence of a single invariant-violating object to create any number of other invariant-violating objects. Yes, but is that a different problem than the global object itself? Why would you expect anything else? And how would introducing an extra set of internal attributes help? Sorry, too much context. I agree about not specifying a new set of internal attributes. I only mean that the WindowProxy must be specified (on the HTML side) so that it doesn't violate these invariants. Regarding the need for these properties to refuse being configured, that seems adequately handled with prose in both ES and HTML, without needing to introduce formal new internal attributes. The ES spec could be silent (with a note) on whether these properties are reported as non-configurable, so that non-browser environments without a WindowProxy don't need to reproduce this insanity.
I agree on the silent+note solution. For web-compat sake and to conform to the non-deletable properties convention, global var/function "should" be reflected as configurable: false. The only reason configurable:true is on the table is for WindowProxy self-hostability, no need to pollute all globals of all environment for that reason.
The sanity check everyone should continue to use is whether the WindowProxy behavior could be self-hosted using direct proxies. In this case, the WindowProxy would need to use the shadow proxy technique. The real target is the hidden window, and the shadow target (the one the proxy itself knows directly) has no non-configurable properties.
Just an adjustement: "no non-configurable properties except [Unforgeable] properties".
The handler refuses to configure any property that is non-configurable on the real target, while continuing to report all these properties as configurable.
An easier solution that would be fine with me is for these "var" and "function" variables to actually be configurable, so that we don't need this odd behavior at all. Brendan is right that this is a breaking change. But is it an important one? I don't know. But it doesn't hurt any integrity issue I care about.
I remember a slideshow where someone had written (and presented to others!) that in JavaScript, memory could be saved by using the "delete" operator on variables. I'm willing to bet that some content on the web relies on 'delete' silently failing on global var-declared variables. If that was the case, then changing var/function globals to be deletable would break the web.
Of course, I personally wouldn't mind being radical and simply forbid proxying the global object altogether. But I assume that you are going to say that there are important use cases. :) Independent of these specific issues, I think that the whole Window vs WindowProxy hack is terrible. If anyone thinks there is any hope of getting rid of this hack, I encourage you to try.
I'm hopeless on this point. I assume that cases where a script holds a reference to an iframe.contentWindow and the iframe at src changes are too numerous to hope for a change.
On 12/17/12 4:51 AM, Mark S. Miller wrote:
Independent of these specific issues, I think that the whole Window vs WindowProxy hack is terrible. If anyone thinks there is any hope of getting rid of this hack, I encourage you to try.
For what it's worth, it's specified that way not least because it's implemented that way in UAs.
And it's implemented that way because other options (like deleting all of the global's properties, including non-configurable ones, on navigation) were a lot worse.
Chances of eliminating navigation from the web platform are 0; I think we can agree on that, right?
So given that, what counterproposals do people have, exactly?
On public-script-coord, Boris Zbarsky showed an example [1] where a global variable is var-defined and then observed to be absent from the global object it was attached to (because the WindowProxy has changed of underlying window object).
The careful ECMAScript 5.1 reader knows that global var-defined variables are supposed to be reflected as own non-configurable properties of the global object. Reflecting the property as such commits the object to keep the property forever which, as we've seen in Boris example, is not compatible with how the web works.
I don't think it'll be possible to change how global objects in same-origin iframes work nor relax ES5 invariants; so my proposal is to have var/let/const/function global declarations reflected as configurable, but acting as if they were not. This would also require a couple of changes in the spec and consequently JS engines and certainly test262. Other proposals welcome, of course.
David
[1] lists.w3.org/Archives/Public/public-script-coord/2012OctDec/0328.html