The global object as the "global scope instance object"

Brendan Eich brendan at mozilla.org
Tue Jan 24 12:59:57 PST 2012


> Andreas Rossberg <mailto:rossberg at google.com>
> January 24, 2012 12:22 PM
>
> Actually, it is possible if this is a check for a primordial,

This isn't about built-ins. But also I don't believe we should move the 
core built-ins to a prototype of the global object. That's an observable 
change since ES3. Maybe not breaking, who knows?

> and you
> move them to the prototype of global this and allow shadowing them.
> Then you'd be able to write:
>
> let foo = Object.getPrototypeOf(this).foo || function() { ... }
>
> (I think we had something like this on the board once.) Or, in the
> browser, if window was actually bound to that prototype,

window === this -- it must be the WindowProxy for the Window object that 
is the global scope.

> this simplifies to:
>
> let foo = window.foo || function() { ... }

This will not work if the detection is coping with prior scripts that 
bound let bindings, since we agreed that you cannot redeclare a given 
identifier using let.

If each script's lexical scope is isolated, then of course there's no 
problem in "redeclaring", but detection breaks. Detection is based on 
objects, not bindings, in this kind of code (there are other detection 
patterns).

> I don't think compatibility can afford binding window to something
> different than global this, though.

Whew! I was wondering.

> (One could still pre-bind the prototype to a different name, however.)

(Do not want.)

> Of course, I sincerely hope that the module system will provide a more
> pleasant replacement for this pattern. :)

But what? If it's let-based I'd like to know how it could work.

/be
>
> Brendan Eich <mailto:brendan at mozilla.org>
> January 24, 2012 11:24 AM
>> Andreas Rossberg <mailto:rossberg at google.com>
>> January 24, 2012 10:32 AM
>>
>> Taken literally, an implicit block scope at toplevel would imply that
>> let/const-bound properties won't show up on the global object at all.
>> That seems to devalue the global object and/or let.
>
> I prefer to think of it as saving 'let' from the degradations of the 
> global object ;-).
>
> I am skeptical we will banish var, ever. Consider the object detection 
> pattern:
>
>   if (!this.foo) {
>     var foo = function () {
>       ...
>     };
>   }
>
> No way to make this work with let.
>>
>> (Part of) what I proposed in the OP of this thread is that for the
>> toplevel, we can still safely reflect let/const bindings on the global
>> object, but through accessor properties -- just like with module
>> instance objects. Solves all the problems we just discussed, while
>> also keeping let useful as the new var.
>
> I saw, clever approach -- haven't had time to evaluate it for 
> compatibility. Seems optimizable.
>
> /be
>
> Andreas Rossberg <mailto:rossberg at google.com>
> January 24, 2012 10:32 AM
>
> Taken literally, an implicit block scope at toplevel would imply that
> let/const-bound properties won't show up on the global object at all.
> That seems to devalue the global object and/or let.
>
> (Part of) what I proposed in the OP of this thread is that for the
> toplevel, we can still safely reflect let/const bindings on the global
> object, but through accessor properties -- just like with module
> instance objects. Solves all the problems we just discussed, while
> also keeping let useful as the new var.
>
> Var would keep its current semantics, aliasing a data property. For
> functions, it doesn't matter much either way, but for consistency with
> other static bindings I'd move to accessor-based semantics in ES6.
>
> /Andreas
>
> Brendan Eich <mailto:brendan at mozilla.org>
> January 24, 2012 9:49 AM
>> Andreas Rossberg <mailto:rossberg at google.com>
>> January 24, 2012 2:37 AM
>> On 23 January 2012 19:25, Brendan Eich<brendan at mozilla.org>  wrote:
>>> Andreas Rossberg<mailto:rossberg at google.com>:
>>>> V8 currently allows
>>>>
>>>>    var w = 1; w = 2; print(w); const w = 3
>>>>
>>>> which will output 2. The idea most likely was that const should behave
>>>> like var. This, and other, similar examples clearly have to break if
>>>> should const become official in classic mode, so the compatibility
>>>> argument may not carry far.
>>> SpiderMonkey:
>>>
>>> js>  var w = 1; w = 2; print(w); const w = 3
>>> typein:19: TypeError: redeclaration of var w:
>>> typein:19: var w = 1; w = 2; print(w); const w = 3
>>> typein:19: ....................................^
>>>
>>> js>  var w = 1
>>> js>  const w = 3
>>> typein:22: TypeError: redeclaration of var w
>>
>> However:
>>
>> js>  const w = 3; var w = 1; print(w);
>> 3
>
> This follows from var not disturbing a pre-existing binding. Or so we 
> thought long ago when adding const, but that was years before const as 
> initialize-only-and-at-most-once let.
>>> Why does V8 do something else, do you know the impetus for diverging?
>>
>> No, unfortunately I don't know the full history there. I can try to 
>> find it out.
>>
>> But just to be obnoxious, with Firefox:
>>
>> print(c);
>> Object.defineProperty(this, 'c', {value: 1});
>> print(c);
>> const c = 2;
>> print(c);
>> =>  undefined 1 2
>
> You bet -- const does redefine the global property, unlike var. This 
> is not something we propose for standardization, of course!
>> Or even:
>>
>> print(c);
>> Object.defineProperty(this, 'c', {value: 1, writable: true});
>> print(c);
>> c = 2;
>> print(c);
>> const c = 3;
>> print(c);
>> =>  undefined 1 2 3
>>
>> Apparently, FF avoids breaking the object model only for the price of
>> keeping the non-writable const property configurable until the actual
>> initialization -- effectively breaking const completely.
>
> More fun:
>
> js> function f(k) {
>   for (var i = 0; i < k; i++) {
>     const j = i*i;
>     a.push(j);
>   }
> }
> js> a = []
> []
> js> f(10)
> js> a
> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>
> SpiderMonkey const has never been initialize-at-most-once. Some people 
> claim to like this, but we are going to try breaking it in favor of ES6.
>
>> Consequently, I maintain my claim that it is impossible to reconcile
>> sane let/const semantics with the idea of having toplevel bindings
>> represented as data properties on the global object.
>
> I agree. For ES4 we equated let to var at top-level, a mistake. For 
> ES6 IIRC you have proposed an implicit block scope at top level (of 
> functions at least, I don't see why not programs as well), whereby let 
> and const bind lexically. Only var and function make global object 
> properties.
>
>>   If there is some
>> trick for "hiding" accessor semantics that doesn't break the object
>> model then I'd be really interested in seeing it. :)
>
> Me too.
>
> /be
>>
> Andreas Rossberg <mailto:rossberg at google.com>
> January 24, 2012 2:37 AM
> On 23 January 2012 19:25, Brendan Eich<brendan at mozilla.org>  wrote:
>> Andreas Rossberg<mailto:rossberg at google.com>:
>>> V8 currently allows
>>>
>>>    var w = 1; w = 2; print(w); const w = 3
>>>
>>> which will output 2. The idea most likely was that const should behave
>>> like var. This, and other, similar examples clearly have to break if
>>> should const become official in classic mode, so the compatibility
>>> argument may not carry far.
>> SpiderMonkey:
>>
>> js>  var w = 1; w = 2; print(w); const w = 3
>> typein:19: TypeError: redeclaration of var w:
>> typein:19: var w = 1; w = 2; print(w); const w = 3
>> typein:19: ....................................^
>>
>> js>  var w = 1
>> js>  const w = 3
>> typein:22: TypeError: redeclaration of var w
>
> However:
>
> js>  const w = 3; var w = 1; print(w);
> 3
>
>> Why does V8 do something else, do you know the impetus for diverging?
>
> No, unfortunately I don't know the full history there. I can try to find it out.
>
> But just to be obnoxious, with Firefox:
>
> print(c);
> Object.defineProperty(this, 'c', {value: 1});
> print(c);
> const c = 2;
> print(c);
> =>  undefined 1 2
>
> Or even:
>
> print(c);
> Object.defineProperty(this, 'c', {value: 1, writable: true});
> print(c);
> c = 2;
> print(c);
> const c = 3;
> print(c);
> =>  undefined 1 2 3
>
> Apparently, FF avoids breaking the object model only for the price of
> keeping the non-writable const property configurable until the actual
> initialization -- effectively breaking const completely.
>
> If the property wasn't configurable, then the initialization would
> need to modify a non-writable, non-configurable data property, which
> is a clear violation of the JS object model. It is what V8 does,
> though. So in V8, the above examples are rejected, but instead,
> objects break.
>
> Consequently, I maintain my claim that it is impossible to reconcile
> sane let/const semantics with the idea of having toplevel bindings
> represented as data properties on the global object. If there is some
> trick for "hiding" accessor semantics that doesn't break the object
> model then I'd be really interested in seeing it. :)
>
> /Andreas
>


More information about the es-discuss mailing list