C#: I miss case fall through


We all have heard time and again that the default case fall through is not good (as in C/C++) and C# does not allow it. There has been enough debate on this but I still differ on this. I used to like it a lot and somehow when I do need to use it the following puts me off big time!!!

switch(value)

{

case 0:

Console.WriteLine(“In case 0\n”);

goto case 1;

case 1:

Console.WriteLine(“In case 1\n”);

goto case 2;

case 2:

Console.WriteLine(“In case 2\n”);

break;

}


I kind of do not buy the statement that case-statement fall through results in issues in the maintainence phase. Its pointed out that fall-through can lead to the following



  1. Developer forgets to add the break at the end and un-intentional fall-through may happen
  2. Case statements cannot be easily reordered as the fall-through execution may vary…

With C lying around for 30 years and C++ over 20 years most developers have got used to adding break at the end of case. In case C# wanted to do something for new developers or for developers moving in from languages like VB, a warning could have been added in case break is missing, asking the developer if fall-through is the intent. This is very similiar to the warning given for the following code

bool hello;

// lots of code….

if (hello = true) // this is why some people use true == hello

   Console.WriteLine(arg);


Warning 1 Assignment in conditional expression is always constant; did you mean to use == instead of = ?


What I also do not understand is the requirement for the break statement at the end of each case in C# even though it does not support fall-through.

switch (arg)

{

case “0”:

Console.WriteLine(0);

//break;

case “1”:

Console.WriteLine(1);

break;

}


The above code fails to compile and you need to uncomment the //break to get it to compile. The error is “Control cannot fall through from one case label (‘case “0”:’) to another” Since the language clearly states that fall-through do not happen then why do I need to add the extra break, it has no purpose and I should not be required to add it. This looks like to have been added to aid C/C++ developers to understand that fall through does not happen. I feel that this error should have been the warning I had mentioned above….


There are a lot of interesting or weird uses of fall-through and the fact that switch can be interlaced with statement blocks (thats in the next post…).

Comments (32)

  1. Anonymous says:

    This is completely off topic but what do you use to format and color the C# code you post? Do you have some automatic tool or do you color it manually?

  2. Anonymous says:

    You can actually simulate fall through by using ‘goto <case label>’. It’s actually a safer version of fall through, since you specify exactly where you want to go to, and so re-ordering the case lines will not be a problem.

    I think that this is why the break statement needs to be added… because you need to explicitly specify whether you want to break out of the switch or transfer to another case.

  3. Anonymous says:

    "What I also do not understand is the requirement for the break statement at the end of each case in C# even though it does not support fall-through."

    FINALLY Someone from Microsoft who states this too! I fully agree with you, ‘break’ after each case statement is the most silliest C# construct out there and the reasoning behind it is IMHO weird as well, indeed to benefit C++ programmers. As if these people don’t know what they’re doing…

    The current syntaxis requires goto statements which is IMHO a very sad compromise. If a language designer requires ‘goto’ to solve an issue, IMHO the language designer should have taken that famous step back and rethink the whole situation. It’s not as if it hasn’t been solved before! 🙂

    "I think that this is why the break statement needs to be added… because you need to explicitly specify whether you want to break out of the switch or transfer to another case."

    Why do you have to explicitly specify you want to break out? There’s no fall through, so the end of the case block is … the end of the case block and thus the end of the switch block.

    Fall through is indeed something which can go wrong when you re-order the case statements. Though the actual question is: WHY do you need fall through? Correct, to REUSE code for several values.

    switch(foo)

    {

    case 1:

    // code which is also to be used by 2

    break;

    case 2:

    // code which is only used by 2

    break;

    }

    it might have been better if it would have been something like:

    switch(foo)

    {

    case 1, 2:

    // code which is also to be used by 2

    case 2:

    // code which is only used by 2

    }

    which is logical, because you specify exactly when a block of code is to be executed, namely when ‘foo’ has the value specified with case. This isn’t possible in C# now, but should be, as it’s more flexible than the current setup. Oh, I didn’t specify ‘break’ in the last example, because I don’t see a need for it, as it’s not necessary to state it anyway, similar to enclose the case blocks in {}

  4. 🙂 I follow the following steps

    I cutomized the CSS for the blog with the following

    PRE

    {

    BACKGROUND: #FFFFFF;

    margin-left: 20px;

    margin-right:20px;

    border:1px solid #000;

    COLOR: black;

    FONT-FAMILY: "Courier New";

    PADDING-LEFT: 12px;

    PADDING-TOP: 12px;

    PADDING-BOTTOM: 12px;

    }

    Then while writing the blog, I first go to the HTML view and type <pre>blah blah</pre>

    I switch back to design view and select the blah blah and paste code that I copied from the VS editor (which also copies formatting to clipboard)

  5. Jeevan goto is never a solution. Its a hack and should be avoided. Write goto label in your case statements and be absolutely sure that some guy trying to maintain your code 3 years down the line will sit and curse you and pary that you rot in hell 🙂

    If goto is the solution it simply means for me that C# does not have support for fall-thru as I’ll never use goto… So the only option for me is that I’ll factor the code into methods and inline call them from the various case statements….

  6. Anonymous says:

    You find also quite strange results with TWO "break;"s – e.g.:

    switch(i){

    case 1: while(true) { something…; break; } break;

    ….

    This will not compile, since "break;" is not (I do not know why) context sensitive and the first occurence will adhere to "case" and not to "while" as one would expect.

  7. Anonymous says:

    if (hello = true) // this is why some people use true == hello

    and other yet just use

    if (hello)

    :p

  8. Anonymous says:

    As I understand it the reason for requiring

    "break" even though fallthrough isn’t supported is so that you don’t end up with code that looks identical and legal in both C/C++ and C# but does two very different things.

    switch(foo) {

    case 1:

    doFoo();

    case 2:

    doBar();

    }

    In C/C++ doBar() would be executed when foo was 1, in C# if break weren’t required it wouldn’t be. Requiring break every time means that C/C++ programmers reading the code – or writing it – don’t have the wrong idea about what it’s going to do.

    (Incidentally, this is the same reason I dislike the name "var" for type inference in C#3. People who know javascript think they know what it does when in fact it does something different. I don’t think the importance of cross-language consistency should be ignored…)

  9. tzagotta says:

    I agree that the break statements are displeasing. I always thought that switch/case were strange in C/C++, and I wish C# would have fixed it better. What would have been more consistent with the overall syntax of the language would have been to have a simple statement after each case, with the possibility of a brace-enclosed complex statement.

    switch (variable)

    {

    case 13:

    Console.WriteLine("13");

    case 15:

    {

    Console.WriteLine("15");

    CallSomeFunction();

    }

    }

  10. Anonymous says:

    It’s very misleading to say it doesn’t have fallthrough. It took me a YEAR to figure out what that meant, because you CANT fall through

    switch(thing) {

    case 1:

    case 2:

    case 3:

    Console.WriteLine("Sup!");

    break;

    case 4:

    Console.WriteLine("Dawg!");

    break;

    }

    You just can’t fall-through with content; empty-fall through is absolutely legal.

    I figure the reason it’s not there is for the same reason we don’t have multiple inheritance: it causes extremely poor design.

  11. Anonymous says:

    Abhinaba: The goto I’m referring to is a special syntax for the switch statement only.

    It’s of the form:

    goto case <case label>;

    See the help for the switch statement for more info.

    Unfortunately, the keyword used here is the same as the much-hated goto keyword, which is probably what prompted your response 🙂

    Unlike the goto keyword, the goto case statement is meant only for moving control to another case in the same switch block. It cannot be used to jump to any arbitrary point in the code.

    So, in a way, you can achieve fall through using the goto case statement, but the code is much more cleaner than the C++ version, since you are explicitly mentioning where the control is flowing to.

  12. Anonymous says:

    tzagotta: I agree about switch not looking like the rest of the language but I think you should go further:

    switch (foo) {

    case (1) {

    }

    case (2, 3) {

    }

    default {

    }

    }

  13. Anonymous says:

    One could argue that the goto case syntax allows you to be explicit about your intent to share cases with other cases, but that could have been achieved with adding a simple keyword, "fall". It could be used in place of a break. It documents intent while not bringing in the baggage and shuddering that the goto keyword does for most developers. Introducing a new keyword that does something very simple and self-documenting is not hard on developers. Some may question the rationale initially, but I bet most won’t be nearly annoyed as with the current situation which since 1.0 has pleased no one.

  14. Anonymous says:

    James, you’re wrong that the current situation "pleases no one". It pleases me 🙂

    Sure, I don’t think it’s 100% ideal, but I think it’s a reasonable compromise between consistency with Java, C and C++, and avoiding the all-too-common pitfall of accidental fallthrough. The only thing I think would be a clear improvement would be to throw away the label-like syntax entirely, as I suggested in my last comment.

    Requiring "break" when fallthrough isn’t intended is a reasonable concession to the fact that there are a lot of users familiar with C, C++ or Java who would otherwise have wrong expectations about the behavior of code that didn’t include it.

    And "goto case" is a perfectly reasonable syntax for explicit fallthrough and people who refuse to use it just because the syntax includes the word "goto" are the same kind of people who refuse use generics in C# because they "look like C++ templates". Irrational, in other words.

    (goto case is more powerful than your hypothetical "fall" keyword because you can have multiple cases all having the same destination. I don’t write switch statements often enough to know if that’s valuable, but it sounds like it might be:

    switch (status) {

    case ERR_CONNECTION_LOST:

    recoverConnection();

    goto case OK;

    case ERR_OOM:

    freeSomeMemory();

    goto case OK;

    case ERR_DATABASE_CORRUPT:

    abort();

    break;

    case OK:

    Console.WriteLine("OK!");

    break;

    }

    )

  15. Anonymous says:

    Amazing!

    I actually made the exact same complain on the exact same day. The start part is that you can assign multiple labels to the start point without use of break. The compiler lets me do this:

    switch(a) {

    case 1:

    case 2:

    dostuff();

    break;

    case 3:

    other();

    break;

    }

    but as you know I can’t add anything between case 1 & 2 without adding the break or the goto 🙁

    A very strange decision indeed.

  16. Anonymous says:

    RIGHT!

    I agree – it is very unpleasant to remember each time to put the break

    The first tim I wrote the switch code – I do not forget

    But if I add another case after few days- I am "errored" by the compiler – and I try some unpleasant thoughts…each time 😉

  17. Anonymous says:

    Stuart, I might have not been clear, but I agree with the continued use of the break keyword. My fall keyword would self describe where you wanted fall through behavior. In all other cases, you would still have to use the break keyword. The switch would still be familiar to most developers since the break statement would be used most of the time. And where they wanted to do a fall-through, they’d use a new keyword that would describe their intent. (I’ve seen a lot of c/c++/java code that does that already by using comments. The compiler doesn’t enforce comments.)

    You are correct that goto case is more flexible, but it’s also more dangerous. The rationale behind the C# teams desire to avoid allowing implicit fall-through was to avoid introducing errors over time into the code. Ironically, a goto statement (including the specific goto case) makes this worse than the original switch construct used in C, C++, and Java. More amusing is the team’s own recommendations say to avoid the goto case statement!

    Their argument to avoid it was that you’d have to scan to see which cases had gotos. I think it’s a bit worse than that. You have to scan to see which ones have gotos and follow their paths to see where else they branch since other cases can include gotos.

    Yes, the fall keyword is limited, but that’s by design. It does the following things:

    * Allows fall-through

    * Documents that intent where the compiler can enforce it

    * Keeps the code easy to follow – the path is top-down versus branching. No possibility of infinite case-recursion.

    My opinion is that if the goal was safety the fall keyword provides more safety while keeping things simple.

  18. Anonymous says:

    Someone said that if you have a switch in the code, there’s a problem with the design…

  19. tzagotta says:

    zzz Said, "Someone said that if you have a switch in the code, there’s a problem with the design…"

    That would mean that every C/C++/C# program I’ve ever written has a problem with the design.

    I would say that I don’t agree with your statement.

  20. I really liked the idea of changing the syntax of switch case as stuart suggested to

    switch (foo) {

    case (1) {

    }

    case (2, 3) {

    }

    default {

    }

    }

    This’ll clearly show the intent and will create no confusion to programmer coming from C/C++.

    As far as zzz comments goes, I’d say the person who said "if you have a switch in the code, there’s a problem with the design" never really wrote code for any real-life system. Switches are used to create look-up table based systems is which a very fast look-up occurs. You can never replace switch with if-else construct when the number of cases are high. In case of C# a dictionary look-up code is emitted when number of cases are high and that is much faster than the corresponding if-else construct.

    For embedded systems seperate code sections (named .switch by some compilers) are emitted which just contains these look-up tables and these are placed in to the faster processor-internal DARAM. I am ranting from my previous experience of good ‘ol embedded programming :). God, I miss those days when people actually cared about memory footprint and CPU usage….

  21. Anonymous says:

    After some more consideration, changing the syntax to include a few options in a single case is not a bad way to go. If it supported ranges, even better.

    The comment zzz made regarding design was most likely referring to the idea of using command and other related patterns to replace switch statements. I would agree that in most cases that switch statements are pieces of code that are crying out to be refactored into a command pattern.

    However, that should not come at the exclusion of making the switch construct more developer friendly.

  22. Girish says:

    For those who believe goto is bad programming practice, you need to work with assembly or similar native languages. More than half of actual deterministic logic utilizes gotos in form of JMP, JZ and JNZs. And well, all your compilers are emitting nothing but machine code which is inherently reliant on these code jumps. And for those who want to differ for managed languages, the runtimes are still dependent on these conditional jumps. The last leg of journey will be JNZs and JZs.

  23. Greg Schmidt says:

    I imagine the break might be required so that if someone is migrating code from C++, the disallowed fall through case is flagged by the compiler as opposed to the compiler just changing the behavior (ie. no fall through) without telling the user.

    One aspect of the "goto" approach is that it is more flexible than fall through as any other case label is allowed to be the target.  Personally, I don’t have a big problem with the "goto" as it’s a very controlled situation.  I suspect some would have a problem with it due to the stigma of it’s name.  What if they had called it "transfer" instead?  I’ll bet fewer people would be complaining.

    — Greg

  24. handan says:

    I imagine the break might be required so that if someone is migrating code from C++, the disallowed fall through case is flagged by the compiler as opposed to the compiler just changing the behavior (ie. no fall through) without telling the user.

    One aspect of the "goto" approach is that it is more flexible than fall through as any other case label is allowed to be the target.  Personally, I don’t have a big problem with the "goto" as it’s a very controlled situation.  I suspect some would have a problem with it due to the stigma of it’s name.  What if they had called it "transfer" instead?  I’ll bet fewer people would be complaining.

  25. Greg Schmidt says:

    Girish wrote:

    [For those who believe goto is bad programming practice, you need to work with assembly or similar native languages. More than half of actual deterministic logic utilizes gotos in form of JMP, JZ and JNZs. And well, all your compilers are emitting nothing but machine code which is inherently reliant on these code jumps. And for those who want to differ for managed languages, the runtimes are still dependent on these conditional jumps. The last leg of journey will be JNZs and JZs. ]

    This is a non-sequitor.  The fact that compilers generate jump instructions has absolutely nothing to do with structured programming.  It’s a bit like saying object oriented programming is a farse because your compiler happens to organize object data into linear arrays.

  26. Greg Schmidt says:

    In regards to the switch statement being an indication of a design flaw…

    Sometimes (but not always) it is.  It is generally considered a design flaw if someone switches based on the type of an "object" that is not represented as such.  For example, let’s say you want to draw different shapes.  Rather than have a case statement based on each type (rectangle, circle, n-gon, etc…), and the body of each case statement do the specialized drawing, it is better to have polymorphic shape classes which respond to the message "draw".

  27. Jay Nair says:

    Here is another argument justifying your statement:

    default:

    {

                               Console.WriteLine("Switch does not match");

                               Environment.Exit(1);

    break;//this is irrelavant code… But hey..C# does not give me an option … 🙁

    }

    Exit(1) and yet I am here adding a "break" Give Me a Break!!

    -Jay

  28. chrono says:

    "This is a non-sequitor.  The fact that compilers generate jump instructions has absolutely nothing to do with structured programming.  It’s a bit like saying object oriented programming is a farse because your compiler happens to organize object data into

    linear arrays."

    Just for the record, I am not singling out anyone, not even the poster I am quoting.  I am speaking to "you" ever-present, not "you" in particular.  I just feel like there is a "bad religion" when it comes to things like this and I have to take a moment to give an alternative voice.

    –I believe what the poster was trying to say was more along the lines of:

    It is foolish to blindly consider any tool completely "bad".

    For example, it is foolish to attempt to tow 2 tons of gravel with a GEO METRO, yes, that is so.  It is foolish to attempt to screw down some drywall with a toothpick.  But anyone that happens to be in the business of hauling gravel or installing drywall can say all day long that "toothpicks are evil" and "Geo Metro’s aren’t worth a tin can".  Does that matter?  Next time I want to clean my teeth or drive from San Francisco to NYC I may consider that these tools are actually valuable.

    It is not constructive to demean tools, or to demean the folks who know how to use them.  It may be true that a tool in the wrong hands is evil. And it may be that there are far too many incapable hands out there.  But the fact remains, there is always a great tool to solve a great problem.  Every tool has it’s place.

    If a developer is incapable of understanding the pitfalls, and/or the proper application of any given tool, I would classify the developer as "evil", not the tool.  I would consider that most likely said developer is lacking in creativity or simply knowledge itself.  There are a lot of situations where code safety and performance, and maintainability can be increased by intelligent and consistent application of any number of "blacklisted" tools or constructs.  Consistency is a much bigger rule than "goto statements are evil".

    As a concrete example, I worked at a company where we were operating in a platform that did not have exception handling.  In this platform, as usual, the trolls of the world insisted that goto was "evil".  However, we were able to achieve a very good analog to exception handling by adding a consistent set of goto handlers in each method.  We also added the ability to obtain call stack information in the event of an error.  These capabilities were well beyond what the language itself supported.

    I assure you that we benefited immensely from these enhancements.  And had we been "in the box" thinkers, we would have had to struggle along without.  Shudder.  Thankfully we had both the knowledge and the creativity to devise the solution.  We consistently applied a tool and our code was clean and efficient.

    We also followed a general rule that "goto should be avoided".  Ok, fine.  It should be.  Outside of this particular construct we generally did not ever use it.  We actually made an effort to ensure the whole team understood what we were doing, why, and why that was the exception not the rule.

    It pains me that we are still left with the unfortunate fact that some tools can be misused and may be dangerous when people who are not careful or knowledgeable take up a task they are actually not cut out for.  Bad things can occur.  And there are far too many "developers" out there who can’t tell the difference.  Maybe because they are not trained to "think" on their own I don’t know.  I do sometimes wonder about all the blind rule preaching going on.

    It is totally acceptable for any of us (or our teams) to choose paths that we feel are inherently safer. But from my perspective blindness is just blindness.  Covering your eyes just makes the whole world that much darker.

    Well, I don’t think that switch statements should fall through without some kind of construct.  goto case is fine, for the exceptions where using it would actually help readability and etc, which are few.  If I spoke spanish I’d be ok with IrAlCaso you know so why not goto case?  Who cares what the name of it is.

  29. Greg Schmidt says:

    To chrono:

    I agree with your comments and nothing you wrote seemed like a rebuttal, so I think you missed my point.  I was not arguing for or against "goto" (in fact in another post above, I wrote that I consider "goto" fine in some limited contexts such as within a switch statement).  My point was that in saying that compilers generate jump instructions, it doesn’t follow that using "goto" is generally good practice for humans.  Compilers do many transformations that would not be generally considered good practice for humans (e.g. re-organizing lines of code for piplining etc.). We’re talking about two completely different levels of abstraction and observations about one don’t generally apply to the other.

  30. Leonardo Leite says:

    Interesting case of using C# switch without writing "break" =P

             switch (hexaLetter)

               {

                   case (char) 65:

                       return 10;

                   case (char) 66:

                       return 11;

                   case (char)67:

                       return 12;

                   default:

                       return hexaLetter – 48;

               }

  31. Joe says:

    Why does Microsoft make changes like this, I only now recently encountered this and find it extremely irritating.

    I really should go back to C++, at least there I was left alone to hang myself instead of having Microsoft attempting to help me…

  32. Paul Somebody says:

    Thank you for your post.

    I have been coding in c# since there was c# and I constantly forget about this issue. Each time it comes up, I scratch my head and wonder why I can't fall through?! What the hell c#?

    The thing I don't like is the removal of a feature. Sometimes you want fall through dammit