Block scoping and redeclarations

Andreas Rossberg rossberg at
Wed Aug 24 02:03:40 PDT 2011

On 23 August 2011 21:18, Brendan Eich <brendan at> wrote:
> 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).

That's fine, although for (1) you probably meant "hoisting of var
across a scope that contains a let binding the same name" (or, if you
assume that let is hoisted to the beginning of its block already, then
you have to be very careful about specifying the exact order in which
all the hoisting happens). And for (2), you have to specify whether
this applies before or after hoisting. In fact, I think it's both,
since I assume that we want to make both of these an error:

{ let x; { var x } }
{ { let x; var x} }

Also, I wouldn't necessarily have regarded catch variables as
"implicitly let-bound". Seems a bit odd, but I guess it's OK to define
it that way if it does the right thing.

>> 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.

Does it really harm migration? I can see only two scenarios that would
end up with an illegal redeclaration:

1) The original function contained a single var x somewhere, and
somebody is adding a let x now -- this is no big deal, since it is a
new variable anyway and can easily be chosen differently. (And in
general, it has to anyway; perhaps better to have a uniform rule of
thumb here.)

2) The original code contained several var x, and somebody starts
changing some of them into let incrementally -- attempting this does
change the meaning of the code and is extremely likely to break it in
subtle ways. It's probably preferable to flag it as an error.

>> * 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.

OK, I'm glad to hear that. :)


More information about the es-discuss mailing list