Why are global variables *non-deletable* properties of the global object?

# Mark S. Miller (17 years ago)

In ES3:

10.2.1 Global Code The scope chain is created and initialised to contain the global object and no others. Variable instantiation is performed using the global object as the variable object and using property attributes { DontDelete }. The this value is the global object.

I was puzzled by the DontDelete in the above spec language. Firefox and Safari seems to disagree:

'foo' in window false

var foo = 3;

'foo' in window true

delete window.foo true

'foo' in window false

I prefer FF and Safari's behavior to the ES3 specified behavior. Which should ES3.1 and ES4 codify as correct? Should we drop the "DontDelete" in the spec language? (Concretely, the current ES3.1 draft reflects the meaning of the ES3 spec by saying that the [[Dynamic]] attribute is false. I'm asking whether we should change this to true.)

# Brendan Eich (17 years ago)

On Jun 19, 2008, at 4:39 PM, Mark S. Miller wrote:

In ES3:

10.2.1 Global Code The scope chain is created and initialised to contain the global object and no others. Variable instantiation is performed using the global object as the variable object and using property attributes { DontDelete }. The this value is the global object.

I was puzzled by the DontDelete in the above spec language. Firefox and Safari seems to disagree:

'foo' in window false

var foo = 3;

'foo' in window true

delete window.foo true

'foo' in window false

How did you test? Try putting this in a Firefox address toolbar:

javascript:alert('foo' in window); var foo = 42; alert(delete foo);
alert(foo)

You will get true (because the var binding -- not initialization --
is hoisted to the top of the program, right after the javascript:),
false (because var makes a DontDelete binding outside of eval), and 42.

I prefer FF and Safari's behavior to the ES3 specified behavior.

Why? Lower integrity is not your style.

Using var in closures for object state has higher integrity than
using plain old properties. This makes closures better in addition to
the name-hiding (private variable) benefits.

Which should ES3.1 and ES4 codify as correct?

I don't believe you've tested what you think you tested. If you are
using the squarefree.com then you're not testing an ES-anything- conformant global object implementation!

Should we drop the "DontDelete" in the spec language?

Absolutely not. Besides giving integrity guarantees to programmers,
it gives implementations (including SpiderMonkey and JavaScriptCore)
optimization opportunities (binding name to slot ahead of time, or on
first among many uses).

# Maciej Stachowiak (17 years ago)

On Jun 19, 2008, at 6:33 PM, Brendan Eich wrote:

On Jun 19, 2008, at 4:39 PM, Mark S. Miller wrote:

In ES3:

10.2.1 Global Code The scope chain is created and initialised to contain the global object and no others. Variable instantiation is performed using the global object as the variable object and using property attributes { DontDelete }. The this value is the global object.

I was puzzled by the DontDelete in the above spec language. Firefox and Safari seems to disagree:

'foo' in window false

var foo = 3;

'foo' in window true

delete window.foo true

'foo' in window false

How did you test? Try putting this in a Firefox address toolbar:

javascript:alert('foo' in window); var foo = 42; alert(delete foo); alert(foo)

You will get true (because the var binding -- not initialization -- is hoisted to the top of the program, right after the javascript:), false (because var makes a DontDelete binding outside of eval), and
42.

Safari will do the same. Global var bindings are most definitely
DontDelete, and should certainly stay that way, in my opinion.

Should we drop the "DontDelete" in the spec language?

Absolutely not. Besides giving integrity guarantees to programmers, it gives implementations (including SpiderMonkey and JavaScriptCore) optimization opportunities (binding name to slot ahead of time, or on first among many uses).

Strongly agreed.

, Maciej

# Brendan Eich (17 years ago)

On Jun 19, 2008, at 6:33 PM, Brendan Eich wrote:

If you are using the squarefree.com then you're not testing an ES-anything- conformant global object implementation!

I meant to hyperlink "shell" after "the squarefree.com" in this
sentence to

www.squarefree.com/shell/shell.html

Indeed it uses eval, which makes var bindings deletable per ES1-3. (I
don't recall the rationale for ES1 making var bindings created by
eval deletable -- it was not something the original Netscape
implementation did.)

# Mark S. Miller (17 years ago)

On Thu, Jun 19, 2008 at 6:33 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Jun 19, 2008, at 4:39 PM, Mark S. Miller wrote: How did you test?

I was indeed using the squarefree shell.

Try putting this in a Firefox address toolbar:

javascript:alert('foo' in window); var foo = 42; alert(delete foo); alert(foo)

You will get true (because the var binding -- not initialization -- is hoisted to the top of the program, right after the javascript:), false (because var makes a DontDelete binding outside of eval), and 42.

I did. Thanks for suggesting that experiment. But given the above behavior, I don't understand

javascript:alert('foo' in window); var foo = 42; window.foo = 43; alert(delete window.foo); alert(window.foo)

I get true, true, undefined.

It seems that the "var foo = 42;" created a DontDelete window.foo property but the "window.foo = 43;" assignment somehow wiped out the DontDelete attribute? Is this correct? Should it be?

I prefer FF and Safari's behavior to the ES3 specified behavior.

Why? Lower integrity is not your style.

It's not yet clear to me which decision better supports integrity.

Using var in closures for object state has higher integrity than using plain old properties. This makes closures better in addition to the name-hiding (private variable) benefits.

I don't understand this paragraph, and it seems crucial. Could you expand? Thanks.

Which should ES3.1 and ES4 codify as correct?

I don't believe you've tested what you think you tested. If you are using the squarefree.com then you're not testing an ES-anything-conformant global object implementation!

I was indeed making that mistake.

Should we drop the "DontDelete" in the spec language?

Absolutely not. Besides giving integrity guarantees to programmers, it gives implementations (including SpiderMonkey and JavaScriptCore) optimization opportunities (binding name to slot ahead of time, or on first among many uses).

I'll probably be happy with that. But I'd like to understand the remaining anomaly above first. If it's considered correct, then I don't see how any of these benefits follow.

# Brendan Eich (17 years ago)

On Jun 19, 2008, at 8:40 PM, Mark S. Miller wrote:

Try putting this in a Firefox address toolbar:

javascript:alert('foo' in window); var foo = 42; alert(delete foo); alert(foo)

You will get true (because the var binding -- not initialization
-- is hoisted to the top of the program, right after the javascript:),
false (because var makes a DontDelete binding outside of eval), and 42.

I did. Thanks for suggesting that experiment. But given the above behavior, I don't understand

javascript:alert('foo' in window); var foo = 42; window.foo = 43; alert(delete window.foo); alert(window.foo)

I get true, true, undefined.

Works correctly (true, false, 43) in Firefox 3 (try it, you'll like
it!).

That looks like a Firefox 2 bug, probably to do with "inner and outer
windows". Don't ask (security requirement of the DOM level 0,
implemented similarly in IE and Firefox, IIRC coming soon to Webkit,
very probably in Opera; but thanks for pointing this out!).

Using var in closures for object state has higher integrity than
using plain old properties. This makes closures better in addition to the name- hiding (private variable) benefits.

I don't understand this paragraph, and it seems crucial. Could you expand? Thanks.

var makes a DontDelete property, unlike assignment expressions or
object initialisers (which desugar to assignments). This is better
for implementations (name to slot optimizations) and for integrity
(although without ReadOnly, the benefit is only knowing that no one
can remove a variable from its scope object -- the value could still
change).

It should even be possible to eval(s) in a scope with var bindings
and be sure those vars were not removed or replaced by s.
Unfortunately a bug in ES3 that I mentioned earlier this week allows
s to replace a var or function its caller's scope with a function
that s defines. This is not supported consistently or at all in
popular implementations. It's fixed in ES4 (see http:// bugs.ecmascript.org/ticket/235).

I'll probably be happy with that. But I'd like to understand the remaining anomaly above first. If it's considered correct, then I don't see how any of these benefits follow.

It's just a bug in Firefox 2.

# Chris Pine (17 years ago)

Brendan Eich wrote:

Works correctly (true, false, 43) in Firefox 3 (try it, you'll like
it!).

That looks like a Firefox 2 bug, probably to do with "inner and outer
windows". Don't ask (security requirement of the DOM level 0,
implemented similarly in IE and Firefox, IIRC coming soon to Webkit,
very probably in Opera; but thanks for pointing this out!).

(true, false, 43) in Opera 9.5

Chris

# Brendan Eich (17 years ago)

On Jun 19, 2008, at 11:20 PM, Brendan Eich wrote:

It's just a bug in Firefox 2.

The bug was bugzilla.mozilla.org/show_bug.cgi?id=369259 in
case anyone is interested.

# Maciej Stachowiak (17 years ago)

On Jun 19, 2008, at 11:20 PM, Brendan Eich wrote:

On Jun 19, 2008, at 8:40 PM, Mark S. Miller wrote:

Try putting this in a Firefox address toolbar:

javascript:alert('foo' in window); var foo = 42; alert(delete foo); alert(foo)

You will get true (because the var binding -- not initialization -- is hoisted to the top of the program, right after the javascript:), false (because var makes a DontDelete binding outside of eval), and 42.

I did. Thanks for suggesting that experiment. But given the above behavior, I don't understand

javascript:alert('foo' in window); var foo = 42; window.foo = 43; alert(delete window.foo); alert(window.foo)

I get true, true, undefined.

Works correctly (true, false, 43) in Firefox 3 (try it, you'll like it!).

Also works correctly in Safari 3.1 and the Safari 4 Developer Preview
(which implements split window support).

, Maciej