- From: Brendan Eich <brendan@mozilla.org>
- Date: Fri, 10 Aug 2012 23:14:01 -0700
- To: Allen Wirfs-Brock <allen@wirfs-brock.com>
- CC: Boris Zbarsky <bzbarsky@MIT.EDU>, public-script-coord@w3.org, es-discuss@mozilla.org
Allen Wirfs-Brock wrote: > On Aug 10, 2012, at 3:25 PM, Brendan Eich wrote: >>> 4) The declaration instantiation rules relating to pre-existing bindings >>> only consider own properties of the global object. Inherited >>> properties of the >>> global object have no effect upon the processing of function and var >>> declarations. >> >> This is the incompatible change from ES1-5.1 and reality that I >> question whether we can get away with. > > True, for var declarations. For function declarations it changed in > 5.1 as a result of > https://bugzilla.mozilla.org/show_bug.cgi?id=577325 which initially > concerned what happens with a global function declaration when there > is an inherited access with the same name. Is the inherited setter > called? We all concluded that it shouldn't. Rule 4 above is > essentially an expression of that idea. Yes, I remember. 'function' always differed from 'var' in JS: it would create the binding (or throw trying, ES5+). > Note this is a real world situation as Jonas notes in > https://bugzilla.mozilla.org/show_bug.cgi?id=781739#c9 : >> Since we are on the subject, a similar thing which have been breaking >> in Firefox but working in Chrome is code which does: >> >> function onmessage(event) { ... } >> >> in global scope in workers. >> >> In Firefox the global scope object has on its prototype chain a >> setter for the 'onmessage' property. However this setter isn't run >> and instead a shadowing variable is declared. >> >> In Chrome the global scope object has the setter on the object >> itself, causing the setter to run. >> >> This caused the page to work in Chrome since the setter is run and >> thus an event handler was registered, while in Firefox a "expando" >> variable is created and nothing else happens. Yeah, once more Chrome scores. In primordial JS, writing function onload(){...} defined an onload handler. WYSIWYG and Occam's razor (perhaps too close a shave). > In this case, firing the setter is perhaps what the programmer wanted, > even if it is a terrible way to accomplish that end. It's not that bad if you start from the DOM level 0, especially window.onload being the same binding as function onload() {}. > However, the opposite could easily be true. The programmer has a > working program with a function declaration for Foo. Sometime latter > the browser adds an unrelated accessor property coincidentally named > Foo to window's prototype. The program stops working when the > declaration doesn't over-ride the inherited property but instead calls > some setter with the wrong shaped function.. Yup. The "on" convention I borrowed from HyperCard, with all lowercase, helps avoid collisions for event handlers. Convention helps, but it's not enough. OTOH the real challenge is not functions (Chrome got it right, I think). The issue is 'var' not creating a shadowing property, or else working because WebIDL does something different from its current spec. >> You didn't give motivation for it. Obviously the motivation involves >> not wanting var declarations to be trumped by >> non-writable/non-configurable properties of the global object's >> prototype or grand-proto, etc. But do we have such properties? > > It started with functions declarations as per bug 577325 between ES5 > and ES5.1. Post ES5 the var issue came up as > https://bugs.ecmascript.org/show_bug.cgi?id=78 The attribute sniffing > logic in the ES5.1 change was about trying to identify properties that > have the characteristics of those created by function declarations > (which should be overwriteable by subsequent declarations) from those > that don't. > >> >> One solution is to say that global proto-properties cannot be >> non-writable. I think that's an effective compatibility constraint >> already. > By restricting [[DefineOwnProperty]] on proto-prototypes?? No, just by convention. Jonas points out that var indexedDB = window.mozIndexedDB || ... || window.indexedDB; still will fail if the engine does not create a shadowing var, because indexedDB is a get-only accessor so the assignment in the initialiser will fail for want of set. >> ES5 made the "own" property from ES3, undefined AKA this.undefined in >> global code, non-writable and non-configurable, but we have separate >> logic to allow 'var undefined;' (which is all over the web). Please >> correct me if I'm mistaken here. This is a different case, because >> "own" and not involving the prototype chain. > > I don't think there is anything special about the global named > undefined. As long as it is a own property of the global object > (which is is spec'ed to be) 'var undefined' is fine because redundant > var declarations don't do anything anything. If undefined was > inherited from window.prototype it would be a different story. Agreed, just noting that const x = 42; var x; is not tolerated in ES6 as proposed (right?). >>> Supporting requirements 3&4 are where the "own" property checks were >>> introduced. >> >> I don't see 3, first sentence, as novel or at issue. If (and only if) >> a new property is bound by var, it will be "own". And function always >> blows away any prior configurable, etc. (10.5 step 5(e)), binding. > > What you just said about functions is how we justified over-riding > inherited function valued properties. Yes. 'function' and 'var' differ. I think we agree -- I hope you're not trying to make 'var' more like 'function'. > But what about var. Rule 3 also means that 'var foo' guarantees you a > own property of the global object. Otherwise we have the var analog > of the the above function Foo issue. That is not a problem so much in practice, until recently :-|. > How do we know whether 'var onClick = null' is intended to call an > inherited setter or to create and initialize a global object property. > Since there is an explicit 'var' that latter seems like a reasonable > guess. LOL, the capital C means you are not touching a window.onclick handler. Plus, no such event handler on window. But you're right, we can't have it both ways. This strongly argues for global WebIDL-inherited properties being "own". I see Jonas posted a followup making the same observation. /be
Received on Saturday, 11 August 2012 06:14:34 UTC