Block scoping and redeclarations

Brendan Eich brendan at
Wed Aug 24 09:03:36 PDT 2011

On Aug 24, 2011, at 2:03 AM, Andreas Rossberg wrote:

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

It doesn't matter whether the hoisting is in the same block, or the var is in a block nested within the let's block (or body) scope.

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

There is no "before and after" or "both" here. Hoisting first, with rule 1 enforced; then rule 2 checking. Relative source order of declarations is irrelevant.

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

That is explicit in ES3-in-reality (ES3 was broken), real engines use block scoped catch variable bindings, and those engines that support 'let' (Rhino and SpiderMonkey at least) use exactly the same block-scoping machinery for catch variables as for let bindings.

We went over this during ES3.1 and ES4 days, here on-list and in TC39 meetings. No problem reiterating, I realize that was long before your time :-).

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

This costs, you are special-pleading. Oh, migrators can absorb *my* preferred tax, for the greater good *I* see. That's not how the game is played.

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

This is indeed the case. Large functions often use var to redeclare canonical short-named variables (loop controls, this is most common with for loops). A new maintainer free to use 'let' may switch, and find trouble anyway (say they change for (var i ...) to for (let i ...) but i is used after the for loop's end). There are no guarantees, but you are adding a speed-bump.

The only upside of the speed-bump is implementor convenience. I do not believe there's any pedagogical gain in practice. I know from our JS1.7+ experience that real code including large functions does mix var and let ("_at all_" as you put it -- not for the same name). Implementors have to take one for the orders-larger developer team.


More information about the es-discuss mailing list