- 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