Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scopes & Closures Ch. 6 - Switch Statement Scoping #1670

Open
ericmathison opened this issue May 25, 2020 · 11 comments
Open

Scopes & Closures Ch. 6 - Switch Statement Scoping #1670

ericmathison opened this issue May 25, 2020 · 11 comments
Labels

Comments

@ericmathison
Copy link

Please type "I already searched for this issue":
I already searched for this issue.

Edition: (1st or 2nd)
2nd

Book Title:
Scope & Closures

Chapter:
Chapter 6: Limiting Scope Exposure

Section Title:
Scoping with Blocks

Problem:

The { .. } curly-brace pair on a switch statement (around the set of case clauses) does not define a block/scope.

As best I can tell, the switch statement curly-braces referred to do create a scope with const or let.

For example, with var, foo outputs 'foo' as expected.

switch (true) {
  case true:
    var foo = 'foo';
}
console.log(foo);

However, with let, logging foo produces a reference error. (Not expected if these braces aren't creating a scope)

switch (true) {
  case true:
    let foo = 'foo';
}
console.log(foo);

This came up in our last online Code Club discussion (which I believe you have visited previously). Thanks so much for providing this resource!

@getify
Copy link
Owner

getify commented May 25, 2020

The cited quote is asserting that the outer pair of { .. } attached to the switch itself does not create a scope. A let / const declaration in a case clause block-scopes the declaration to that case clause specifically, but the outer switch statement itself is still not a block of scope.

If there are no { .. } surrounding the case clause's list of statements, then this list of statements itself acts like a block-scope (though not technically a block).

IOW, this is not a block-scope (and also not syntactically allowed):

switch (true) {
   // not block scoped to the switch (but also syntactically disallowed)
   let foo = 42;
   console.log(foo);
}

But this is a block-scope:

switch (true) {
   case true:
      // the scope here is the `case` clause, specifically its statement list, even
      // without any explicit { }
      let foo = 42;
      console.log(foo);
}

@ericmathison
Copy link
Author

If case statements implicitly create a scope, I'd expect this to produce a reference error (via fallthrough):

switch (true) {
   case true:
      let foo = 42;
    case 'anyvalue':
      console.log(foo);
}

Unexpectedly however, it ouputs 42. (Which unfortunately doesn't satisfy my ultimate questions of life, the universe, and everything in this case 😆)

@getify
Copy link
Owner

getify commented May 25, 2020

Welp... I'm stumped. That's not what I understood.

@getify
Copy link
Owner

getify commented May 25, 2020

According to the spec, the { } around the case statements are not a block -- well, sorta, it's a special CaseBlock entity -- and the parsed AST does not have a "block" element for this node... but nevertheless a scope is created. So I was both correct and incorrect in the same sentence. Bonkers that TC39 chose to make that nuance. Shrugs. Definitely don't ever do that in a program, it's a terrible idea for confusion sake.

@ericmathison
Copy link
Author

Ok. Appreciate you taking the time to look into this. Thanks again for all your work on the book and for making it available online! If you ever have time to join us again some time let us know!

@getify getify added the errata label Jul 16, 2020
@ghost
Copy link

ghost commented Aug 25, 2020

@getify this project seems like fun. I want to contribute. How do i go about that? The documentation is not quite self sufficient

@getify
Copy link
Owner

getify commented Aug 25, 2020

@karenefereyan This isn't really a "project" per se. It's a series of books I wrote (and am writing). Contributors are primarily those who find typos that my copyeditor may have missed, or occasionally find technical mistakes (such as this thread).

As for contributing in that capacity, see these guidelines.

@danqulogy
Copy link

If case statements implicitly create a scope, I'd expect this to produce a reference error (via fallthrough):

switch (true) {
   case true:
      let foo = 42;
    case 'anyvalue':
      console.log(foo);
}

Unexpectedly however, it ouputs 42. (Which unfortunately doesn't satisfy my ultimate questions of life, the universe, and everything in this case 😆)

Switch is a structural directive which natively defines how it handles execution - matched cases should execute. The case items themselves should be seen as they are all in one scope. This means each case acts like a piece of code that will execute when the it case matches the switch clause, all cases are in a transient scope under the switch directive, so ideally the switch can be called a block and not a scope.

@getify
Copy link
Owner

getify commented Aug 25, 2020

The case items themselves should be seen as they are all in one scope.

This isn't entirely true, since if you put { .. } around the statements of a single case clause, that is a nested block-scope.

@ghost
Copy link

ghost commented Aug 26, 2020

@karenefereyan This isn't really a "project" per se. It's a series of books I wrote (and am writing). Contributors are primarily those who find typos that my copyeditor may have missed, or occasionally find technical mistakes (such as this thread).

As for contributing in that capacity, see these guidelines.

Okay thanks

@danqulogy
Copy link

The case items themselves should be seen as they are all in one scope.

This isn't entirely true, since if you put { .. } around the statements of a single case clause, that is a nested block-scope.

I understand it is scope when you put {...} around the statements. But the whole list of cases acts as if they are in one scope inside the switch when the case bodies are one-liner expressions as commented by @ericmathison

switch (true) {
   case true:
      let foo = 42;
    case 'anyvalue':
      console.log(foo);
}

Outputs 42

But when we put them in curly braces, scoping rules is effected:

switch (true) {
   case true:
      { let foo = 42; }
    case 'anyvalue':
      { console.log(foo); }
}

Throws an error
Uncaught ReferenceError: foo is not defined

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants