Block scoping and redeclarations

Brendan Eich brendan at
Tue Aug 23 12:18:58 PDT 2011

On Aug 23, 2011, at 5:31 AM, Andreas Rossberg wrote:

> However, there are various possibilities to interpret this. Assume
> that each line in the following is a function scope:
> { let x; var x }  // 1a
> { var x; let x }  // 1b
> { let x; { var x } }  // 2a
> { var x; { let x } }  // 2b
> { { let x } var x }    // 3a
> { { var x } let x }    // 3b
> { { let x } { var x } }  // 4a
> { { var x } { let x } }  // 4b

As var hoists to function scope, the order doesn't matter, so what Allen said: 1[ab], 2a, 3b all should fail with early error (yeah, SyntaxError -- what else? :-P), while 2b, 3a, and 4[ab] all succeed.

> There are lots of arguments that can be made here, but ultimately, my
> feeling is that any rule that allows some of the examples above, but
> not others is both brittle and confusing, and potentially too
> complicated to memoize correctly for the average programmer.

I think the rules we have discussed are:

1. Any hoisting of var across let binding the same name (whether explicit, or as in catch blocks and comprehensions, implicit) is an early error.

2. Redeclaration of a name in the same block scope via let, const, or function-in-block is an error.

That's it. Shadowing via let, const, and function-in-block is allowed (alpha conversion).

> Consequently, we propose a very simple rule instead:
> * It is a syntax error if a given identifier is declared by both a
> let-declaration and a var-delaration in the same function. (And
> similarly, for const vs. var, or function vs. var -- the latter being
> an incompatible change for the global scope, but it seems like we may
> abolish that anyway.)

Anywhere in the same function? This seems unnecessarily restrictive. People will migrate large functions into ES6 and start let-converting while maintaining. We have seen this happen over the last five years in which we've supported let, in Firefox front-end and add-on JS.

> We could go even further with the first point: we could make it a
> syntax error to mix var and let _at all_ in a single function,
> regardless of what identifiers they declare. I would be perfectly fine
> with that, too, but expect that others would disagree.

You got that right ;-).

> * In a similar vein, I think we should probably forbid `var' to
> coexist with _any_ other form of binding for the same variable in a
> single function. In particular, for Harmony mode we should rule out
> the infamous "try .. catch(x) { var x = 666; ...}".

That is covered by my (1) above, no need for special cases. The catch variable is an implicit let binding.

> * Finally, do we allow redeclaring functions with let or const, like
> it used to be the case with var? I propose disallowing it.

That's also been a point of recurring TC39 agreement, specifically to future-proof for guards.


More information about the es-discuss mailing list