Jaa


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");        gotocase 1;     case 1:        Console.WriteLine("In case 1\n");        gotocase 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

  • Anonymous
    November 14, 2005
    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?

  • Anonymous
    November 14, 2005
    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.

  • Anonymous
    November 14, 2005
    The comment has been removed

  • Anonymous
    November 14, 2005
    :) 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)

  • Anonymous
    November 14, 2005
    The comment has been removed

  • Anonymous
    November 14, 2005
    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.

  • Anonymous
    November 14, 2005
    if (hello = true) // this is why some people use true == hello

    and other yet just use

    if (hello)

    :p

  • Anonymous
    November 15, 2005
    The comment has been removed

  • Anonymous
    November 15, 2005
    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();
    }
    }

  • Anonymous
    November 15, 2005
    The comment has been removed

  • Anonymous
    November 15, 2005
    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.

  • Anonymous
    November 15, 2005
    The comment has been removed

  • Anonymous
    November 15, 2005
    The comment has been removed

  • Anonymous
    November 15, 2005
    The comment has been removed

  • Anonymous
    November 16, 2005
    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.

  • Anonymous
    November 16, 2005
    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 ;-)

  • Anonymous
    November 16, 2005
    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.

  • Anonymous
    November 16, 2005
    Someone said that if you have a switch in the code, there's a problem with the design...

  • Anonymous
    November 16, 2005
    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.

  • Anonymous
    November 17, 2005
    The comment has been removed

  • Anonymous
    November 17, 2005
    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.

  • Anonymous
    March 13, 2008
    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.

  • Anonymous
    August 29, 2008
    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

  • Anonymous
    September 03, 2008
    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.

  • Anonymous
    January 05, 2009
    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.

  • Anonymous
    January 26, 2009
    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".

  • Anonymous
    February 08, 2009
    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

  • Anonymous
    May 19, 2009
    The comment has been removed

  • Anonymous
    June 08, 2009
    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.

  • Anonymous
    May 26, 2010
    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;            }

  • Anonymous
    June 14, 2012
    The comment has been removed

  • Anonymous
    January 02, 2015
    The comment has been removed