let/const in switch cases

Brendan Eich brendan at mozilla.org
Thu Aug 9 20:48:11 PDT 2012


Luke Hoban wrote:
> According to the current draft spec text 'let'/'const' are allowed in the statement list of a switch case, but contribute to the block scope of the outer block.  This can lead to some confusing situations:
>
> function(x) {
>     do {
>          switch(x) {
>              case 0:
>                  return x;
>              case 1:
>                  let x = 'let';
>          }
>      } while (foo());
> }
>
> The 'x' in 'case 0' here will bind to the later 'let x',

That's right, let hoists to braced body or block top -- explicit is 
better than implicit.

I did this in JS1.7 and we've had years of experience with it, in 
SpiderMonkey and Rhino. Alternative of implicit per-"case" scope does 
not work due to C-like fall-through inherited via Java. Programmers do 
write let in case- and default-labeled statement lists in switches in 
Mozilla-specific code and I've never heard of a usability problem.

We could be restrictive (more below), but you have to make a usability 
or implementation hardship case. I don't think you have.

>   but depending on which case executes first, this may or may not trigger an error on accessing x before it is defined.  This is the only place in the language where a reference to a let binding declared in the same block scope as the reference cannot be statically understood to be a valid vs. invalid read.

Sure, but why did you exclude closures?

Closures can nest in blocks and capture let and const, and use a let or 
const binding before it has been initialized. Closures are a big part of 
JS. The "declared in the same block ... as the reference" is therefore 
too narrow as an objection to the infeasibility of statically analyzing 
let-in-switch.

Without such narrow special pleading, we have with the temporal dead 
zone a use-before-init rule that cannot be statically analyzed, period. 
Closures are enough, switch is not novel. If it has other issues, let's 
argue about them, but this one is off target due to closures.

>    This is both likely to cause confusion for developers, and adds implementation complexity.

Not in our actual, >5-years-long experience. Examples:

http://dxr.mozilla.org/mozilla-central/b2g/chrome/content/forms.js.html#l50
http://dxr.mozilla.org/mozilla-central/b2g/chrome/content/shell.js.html#l290
http://dxr.mozilla.org/mozilla-central/b2g/chrome/content/shell.js.html#l300
http://dxr.mozilla.org/mozilla-central/b2g/chrome/content/shell.js.html#l301 
etc.
http://dxr.mozilla.org/mozilla-central/toolkit/components/places/nsPlacesExpiration.js#l931
http://dxr.mozilla.org/mozilla-central/services/sync/modules/engines/tabs.js#l303
and many others...

Programmers can do this with var and they expect to do the same with let.

> There's an argument to be made that switch case StatementLists should not be allowed to include Declarations.  This would make the code above a syntax error, and require putting {} around the case if 'let'/'const' were needed.

We considered that back in the ES4 era, but it is onerous. Lots of vars 
in sub-statements, and people reasonably expect to write let 
declarations the same. There is a braced body-block to scope such let 
declarations. Typically the case "arms" have disjoint declarations, and 
programmers definitely know to use a block to avoid colliding.

>    This also aligns with all other occurrences of nested statements that are not surrounded by {} in the grammar, for example, 'if(true) let x = 3'.

Yes, but switch is different. It has a braced body. Its statement-lists 
have fall through so the more relevant "if" comparison would be 
something like

   {
     let x = 42;
     if (y)
       x = 43;
     alert(x);
   }

which is perfectly legal in ES6 and any Harmony or ES4-era proposal.

>    Current Chrome builds appear to follow this approach, reporting that the 'let' in the initial code sample above appears in an 'unprotected statement context'.

Are we all trying to follow the draft spec, or not? Thanks for proposing 
to change it first. Implementations deviating without talking first = 
disharmony.

/be


More information about the es-discuss mailing list