Violations of internal method invariants?
It seems you're right (reproduced on Chrome and Safari). These examples clearly violate all the invariants related to non-configurable properties.
If I understand correctly, the form DOM element's named input properties 'shadow' the actual JS properties defined on the DOM object. Even if the DOM object defines a non-configurable "foo" property, adding an input element with the name "foo" will shadow the non-configurable property with a configurable one (and removing the input element again reveals the old non-configurable JS property).
This seems bad. I'm not a DOM expert, but is it essential that the form elements have two distinct namespaces (the namespace for named input elements and for regular JS properties), or is this just a side-effect of how they happen to be implemented?
On 7/31/14, 1:53 AM, Tom Van Cutsem wrote:
If I understand correctly, the form DOM element's named input properties 'shadow' the actual JS properties defined on the DOM object.
That certainly seems to be what some UAs do, yes.
This seems bad. I'm not a DOM expert, but is it essential that the form elements have two distinct namespaces (the namespace for named input elements and for regular JS properties), or is this just a side-effect of how they happen to be implemented?
That's an interesting question.
Gecko has totally different behavior here (we don't allow the form's named inputs to shadow own properties of the form if someone managed to define those, but will throw if you try to define a property for whose name we already have a named input.
And the Web IDL spec has yet another approach to this whole thing: It simply coerces "configurable" to true in its custom [[DefineOwnProperty]] for these sorts of objects (but keeps effectively separate namespaces).
I believe that the one shared feature between Gecko, the spec, and the IE/Chrome implementation is that if you set a property "foo" on the form, then add an input with name="foo", then remove the input, the value you set initially will still be there. Actually, the same is true in Safari, as long as you don't observe "form.foo" while the input is in the form.
Requiring a single namespace, such that adding an input and then removing it would make a previous property with the same name as the input go away, would actually be fairly annoying performance-wise, I suspect.
In any case, I would be very interested in figuring out what sane (sane-enough?) behavior UAs are willing to converge on here so we can actually spec it.... If anyone has suggestions for what that behavior should be, I'd love to hear them. Since every UA except Gecko certainly needs to change something here no matter what, seems like we might as well all change in the same direction.
On Thu, Jul 31, 2014 at 1:23 AM, Boris Zbarsky <bzbarsky at mit.edu> wrote:
And the Web IDL spec has yet another approach to this whole thing: It simply coerces "configurable" to true in its custom [[DefineOwnProperty]] for these sorts of objects (but keeps effectively separate namespaces).
Interesting. This approach doesn't seem quite kosher.
ES6 lists some invariants here that apply to all objects, even host objects: people.mozilla.org/~jorendorff/es6-draft.html#sec-invariants-of-the-essential-internal-methods
There's not a rule that says flat-out, "If Desc.[[Configurable]] is false and [[DefineOwnProperty]](P, Desc) returns true, that counts as 'observing' the property P as a non-configurable property on the target." but if you take that as read, what WebIDL is doing here is banned.
Note that steps 14-22 of 9.5.6 (Proxy#[[DefineOwnProperty]]) do some checks which enforce this rule. people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc
Tom, can the prose be improved? What's the intent?
On Thu, Jul 31, 2014 at 1:23 AM, Boris Zbarsky <bzbarsky at mit.edu> wrote:
Requiring a single namespace, such that adding an input and then removing it would make a previous property with the same name as the input go away, would actually be fairly annoying performance-wise, I suspect.
Really? There are web pages that add inputs to forms in a tight loop?
In any case, I would be very interested in figuring out what sane (sane-enough?) behavior UAs are willing to converge on here so we can actually spec it.... If anyone has suggestions for what that behavior should be, I'd love to hear them.
Right Thing: I think [[PreventExtensions]] on these objects should always return false. I think [[DefineProperty]] on these objects should return false if Desc.[[Configurable]] is false or if it's missing and would default to false. That'll cause Object.freeze(form) and Object.defineProperty(form, "x", {configurable: false}) to throw a TypeError. Seems legit.
Alternative: Specify what Gecko does. Make non-configurable properties on these objects shadow even the named getter.
At the moment, I don't see anything else that would preserve the object invariants.
2014-07-31 15:26 GMT+02:00 Jason Orendorff <jason.orendorff at gmail.com>:
There's not a rule that says flat-out, "If Desc.[[Configurable]] is false and [[DefineOwnProperty]](P, Desc) returns true, that counts as 'observing' the property P as a non-configurable property on the target." but if you take that as read, what WebIDL is doing here is banned.
Note that steps 14-22 of 9.5.6 (Proxy#[[DefineOwnProperty]]) do some checks which enforce this rule.
Tom, can the prose be improved? What's the intent?
The intent is indeed that if [[DefineOwnProperty]] returns true for a non-configurable descriptor, then the client can count on the property being defined as a non-configurable property. It would not be OK for a proxy to tamper with the descriptor that the client passed in (e.g. by coercing configurable to "true") and then signalling success, which seems to be what WebIDL is doing here.
The prose says: "A property cannot be added as or modified to be non-configurable, if it does not exists as a non-configurable own property of the target object."
Possibly we need to make more explicit the fact that "added as non-configurable" pertains to the original attribute state that the client passed in.
2014-07-31 15:43 GMT+02:00 Jason Orendorff <jason.orendorff at gmail.com>:
Right Thing: I think [[PreventExtensions]] on these objects should always return false. I think [[DefineProperty]] on these objects should return false if Desc.[[Configurable]] is false or if it's missing and would default to false. That'll cause Object.freeze(form) and Object.defineProperty(form, "x", {configurable: false}) to throw a TypeError. Seems legit.
+1. They key point is that [[DefineOwnProperty]] should not try to coerce configurable:false to configurable:true. It should just reject such property updates.
On 7/31/14, 9:43 AM, Jason Orendorff wrote:
On Thu, Jul 31, 2014 at 1:23 AM, Boris Zbarsky <bzbarsky at mit.edu> wrote:
Requiring a single namespace, such that adding an input and then removing it would make a previous property with the same name as the input go away, would actually be fairly annoying performance-wise, I suspect.
Really? There are web pages that add inputs to forms in a tight loop?
Sure. Simple example: a page that has a table. The table is in a form and is used to organize and lay out the controls. The table has a few hundred rows, each with several controls in it.
The page has UI to sort the table rows; it does this by reordering them in the DOM using insertion sort.
This is not a hypothetical example, by the way; I've certainly profiled pages of this sort before.
Right Thing: I think [[PreventExtensions]] on these objects should always return false.
The Web IDL spec requires this already, fwiw:
Platform objects implementing an interface that supports indexed or named properties cannot be fixed; if Object.freeze, Object.seal or Object.preventExtensions is called on one of these objects, the function MUST throw a TypeError.
If there is an actual hook it can hook into now to do that, so much the better.
I think [[DefineProperty]] on these objects should return false if Desc.[[Configurable]] is false or if it's missing and would default to false.
This is not compatible with the HTML spec, sadly (and neither is the spec, as a result) for the following reason: HTMLDocument needs to be able to have a non-configurable own accessor property named "location".
It looks like Safari and Chrome do not implement this part of the spec (from www.w3.org/Bugs/Public/show_bug.cgi?id=19560), for what
that's worth, but get the web compat behavior actually needed via not following the HTML spec for other parts of named access on Document.
The simple thing here would be to return false unless the property name is one of the ones that Web IDL defines as unforgeable on the object.
Alternative: Specify what Gecko does. Make non-configurable properties on these objects shadow even the named getter.
This is needed for HTMLDocument, as long as it has a non-configurable "location" property.
On Thu, Jul 31, 2014 at 1:24 PM, Boris Zbarsky <bzbarsky at mit.edu> wrote:
On 7/31/14, 9:43 AM, Jason Orendorff wrote:
Right Thing: I think [[PreventExtensions]] on these objects should always return false.
The Web IDL spec requires this already, fwiw: [...]
If there is an actual hook it can hook into now to do that, so much the better.
Great. Please pass along to the WebIDL editor(s) that this can be done by specifying that [[PreventExtensions]] returns false.
I think [[DefineProperty]] on these objects should return false if Desc.[[Configurable]] is false or if it's missing and would default to false.
This is not compatible with the HTML spec, sadly (and neither is the spec, as a result) for the following reason: HTMLDocument needs to be able to have a non-configurable own accessor property named "location".
If "location" is exempt from shadowing, then it can be exempt from the restriction too. That solves the problem, right?
On 7/31/14, 2:47 PM, Jason Orendorff wrote:
Please pass along to the WebIDL editor(s) that this can be done by specifying that [[PreventExtensions]] returns false.
Excellent. www.w3.org/Bugs/Public/show_bug.cgi?id=26490
If "location" is exempt from shadowing, then it can be exempt from the restriction too. That solves the problem, right?
Yes.
I was trying to determine what browsers do with named properties on <form> elements, and I'm getting some rather strange results.
Consider bugzilla.mozilla.org/attachment.cgi?id=8463423 and bugzilla.mozilla.org/attachment.cgi?id=8463432
Is it just me, or do Chrome and IE violate the internal method invariants on the first of those, and all three of Chrome, IE, Safari violate them on the second one?