105

When I create a switch statement in VS2008 C# like this (contrived):

switch (state) {
    case '1':
        state = '2';
    case '2':
        state = '1';
}

it complains that I'm not allowed to drop through:

Control cannot fall through from one case label ('case '1' (0x31):') to another

If you're not allowed to drop through, then what is the purpose of the break statement at all? Why didn't the language designers just leave it out and automatically jump to the end of the switch statement instead of forcing us to put in an unnecessary construct?

CharlesB
  • 86,532
  • 28
  • 194
  • 218
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953

4 Answers4

90

Basically to make it more familiar to C/C++/Java developers. Personally I think it was a mistake, but that's the reasoning.

I would have preferred a forced block:

case '1':
{
}

Aside from anything else, that would have avoided the weird variable scoping situations for switch/case. You could still have multiple case labels, of course:

case '0':
case '1':
{
}

It might also be nice to be able to list multiple cases more simply:

case '0', '1':
{
}

Oh, and a slight nit-pick about your description of the existing language: you don't have to have a break. It's just that the end of the case has to be unreachable. You can also have throw, goto or return. There may be others that I've missed, too :)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    @Jon +1 - Never knew you could do that! – djdd87 Jun 24 '10 at 10:01
  • 1
    I think it's a good decision not to make identically looking constructs behaving differently. That would be a hell for programmers who have to switch languages frequently. – Erich Kitzmueller Jun 24 '10 at 10:03
  • I also like the '0', '1' syntax. The D programming language has a much nicer switch IMO: http://www.digitalmars.com/d/2.0/statement.html#SwitchStatement It allows case 1,2,3: and case 1: .. case 10 for from to – simendsjo Jun 24 '10 at 10:05
  • @Jon - never mind, I completely misread your answer. "I would have preferred a forced block"... I thought you said you could use a code block. I got a bit over excited there. – djdd87 Jun 24 '10 at 10:23
  • @GenericTypeTea: You certainly *can* put a block there even now - but you'll still need a break, and you aren't *forced* to use a block. – Jon Skeet Jun 24 '10 at 10:27
  • @Jon - the braces are pretty redundant in C# then? So, what you're saying is that it would of made more sense if they would auto-break for you, thereby negating the need to write `break;return;throw;etc;` every time? – djdd87 Jun 24 '10 at 10:47
  • 1
    @GenericTypeTea: No, they're not redundant: they define a new scope. As it is, variables declared "directly" in the case are in the scope of the whole switch statement, which is weird. I'd like the braces to be enforced, but for that to effectively have an automatic break. You would still be able to return or throw if necessary. – Jon Skeet Jun 24 '10 at 11:06
  • @Jon - Thanks for the explanation! Nice to learn something new about such a fundamental aspect of the language. – djdd87 Jun 24 '10 at 11:44
  • I agree, the scoping for switch statements is confusing. It leads me to have to declare a bunch of variables before I begin the switch block. Although it does point out something not immediately obvious: that the runtime can use a variable as soon as it's in scope, not only below that line of code - this is something that can seem odd when debugging and moving the line of execution around. – LoveMeSomeCode Jun 24 '10 at 12:31
  • 1
    Perhaps the best solution would have been for a /switch-section/ to take an /embedded-statement/ rather than a /statement-list/. It would then match `if`, `while`, `for`, etc. No break would be required. You get one statement. More than that, and you put braces. That would have been awesome. – Jeffrey L Whitledge Jun 24 '10 at 13:56
  • @Jeffrey - in other words, a Pascal case statement. – Muhammad Alkarouri Jun 25 '10 at 09:13
77

From the horse's mouth (MSDN) Why is the C# switch statement designed to not allow fall-through, but still require a break?.

Quoting the salient bits, this is why they don't allow fall-through:

This implicit fall-through behavior is often used to reduce the amount of code needed and often isn't an issue the first time that code is written. However, as code moves from the initial development phase into a maintenance phase, the code above can lead to subtle errors that are very hard to debug. These errors result from the very common mistake of the developer adding a case, yet forgetting to put a break at the end of the block.

In C#, the switch statement requires that explicit flow control occur at the end of a case, either a break, goto, return, or throw. If the developer desires fall-through semantics, it can be achieved by an explicit goto at the end of a case statement.

And this is why it's not automatic:

As a result of the C# rules requiring explicit flow-control to occur at the end of a case block (most usually a break), many people question why the behavior simply wasn't changed such that fall-through didn't occur. That is, don't make break required, simply change the semantics of switch to not have fall-through for cases. The reason this wasn't done was so that developers who were very used to C++ wouldn't have a hard time understanding what a switch statement was doing.

Community
  • 1
  • 1
Alex K.
  • 171,639
  • 30
  • 264
  • 288
  • 1
    The link is no longer active. – Millie Smith Jun 16 '14 at 18:47
  • 2
    http://web.archive.org/web/20110515005800/http://msdn.microsoft.com/en-us/vcsharp/aa336815.aspx – Alex K. Jun 16 '14 at 18:52
  • 13
    And now, 7 tears after this was written we see how dumb this decision was. Now we are introducing pattern matching, a hot-new concept that they decide to co-opt `switch` syntax for and is now bogged down by a decision made to "not confused c++ programmers 2 decades ago". Not the best choice, c# team. – George Mauer Nov 27 '17 at 17:26
53

You are allowed to drop through, but you have to do so explicitly with the goto keyword:

switch (state) {
    case '1':
        state = '2';
        goto case '2';
    case '2':
        state = '1';
        break;
}

You can break or gotoin C#, but what you cannot do is not state which you want, because that's a potential source of hard-to-spot bugs.

It's a lot easier to spot that your code says goto when you wanted break (or vice versa) than it is to spot that you forgot to add either.

It might sound stupid, but many a tired two-hour search for the cause of a C++ bug ends in a sudden realisation that you forgot to add a break and your code is falling through all the time. C# avoids that by forcing you to state what you want.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Chris
  • 4,661
  • 1
  • 23
  • 25
  • 2
    I'm embarrassed I didn't know you could 'continue'. Just thought it was illegal to avoid all fall through bugs... Thanks :) – simendsjo Jun 24 '10 at 10:19
  • 3
    Did you try this code? It doesn't compile. You can do "goto case '2'" though. – Jon Skeet Jun 24 '10 at 11:07
  • Gives me "No enclosing loop out of which to break or continue" – Alex K. Jun 24 '10 at 11:28
  • 2
    Actually, you may be right, my test _is_ within a while loop (I plugged it into my current project). That means this won't drop through so much as restart the loop - that would be a very annoying bug :-) – paxdiablo Jun 24 '10 at 11:30
12

If you don't have any code in case 1, you are allowed to fall through, so you can say that "all of these cases share this piece of code"

simendsjo
  • 4,739
  • 2
  • 25
  • 53
  • But in that case you will not get a warning. The compiler is warning you about something it can infer. – Kobi Jun 24 '10 at 10:01