Freigeben über


'switch' in C#

On Eric's blog, a discussion about 'switch' statements in C# & why they require 'break' inspired this post.

One of my favorite principles in the design of C# is that it forces you to be explicit when that removes confusion. The best example is the way that the language doesn't let you accidentally override a base method. If you don't explicitly say what you want, the compiler tells you about it.

In this case, the language is forcing you to be explicit again. Either you're done ("break") or you want to fall through ("goto"). You gotta say which one.


I don't worry too much about the syntax of 'switch' when I code. Instead, I try to have as few 'switch' statements as possible.

The OO way to do things is to use polymorphism to manage differences between cases, not a big decision statement. As soon as I find that I'm switching on the same thing twice, it's time to consider polymorphism. See ReplaceTypeCode*.

And the procedural way is to give each option a name (make them new methods). If I have a switch where the bodies of the cases get even slightly interesting, the whole switch gets out of control. So, at the very least, I want to Extract Method on each body.

In the ideal, I have relatively few switches with only trivial content.

We did something in Whidbey to help switch lovers. We’ll generate cases from an enum.

1. Type ‘switch’.

2. Hit TAB.
This will expand a code snippet with the skeleton of a switch statement. The expression to switch on will be highlighted as an entry field.

3. Supply your favorite enum-typed variable.

4. ENTER (to commit the expansion)

We spit out a ‘case’ block for each value in the enum.

We could have done more. We could have automatically spit out ‘break;’ as soon as you type case. I think that would have made people’s concerns about the superfluous ‘break’ in C# go away. When the editor takes care of it for you, it’s not a big deal. Maybe next time.

In general, I think it’s important that the language designers think about the editing context. If you intend your language to be edited “dumb” editor (like notepad), a semi-intelligent one (emacs, slickedit), or a very intelligent one (VS, eclipse), you would design differently. If you assume certain facilities in the editor, you can take advantage of them to make the language easier to read & easier to write.

Comments

  • Anonymous
    November 14, 2004
    The comment has been removed
  • Anonymous
    November 14, 2004
    At least the designer of C# didn't force us to explicitely declare local variables as in Pascal... ;-)
  • Anonymous
    November 14, 2004
    Radu has a good argument. Playing further on this, we should have:

    foreach(string s in strings)
    {
    //do something...
    continue; //no, I don't want to break.
    }

    Why a missing break in a switch should confuse anyone, confuses me.
  • Anonymous
    November 14, 2004
    A warning about a case-fallthrough would have been enough, yes - but demanding a break is ok for me, too.
  • Anonymous
    November 15, 2004
    Radu: I disagree. The end of the function always does a return. The end of a case-block either does a break or a goto, there's a choice to declare.

    Uwe: C# doesn't require you to declare your locals?
  • Anonymous
    November 15, 2004
    One simple explanation for a bad design:
    99.9999% of the cases won't be fall-through.
    Poll the world.
  • Anonymous
    November 15, 2004
    I have to agree with you jaybaz, the reason I love the break in the switch statement is it explicitly tells you where you want it to go. It increases readability.

    One thing i do not like about the switch statement and break is the compiler warning from it if you are issuing a return in the case. The break gets flagged as unreachable code. Which yeah it is. But still to be consistant it should be there.

    For Example

    switch (x)
    {
    case 1:
    return something;
    break; // <Will get flagged by compiler and issue warning as unreachable code.
    case 2:
    somethingElse = something;
    break; // is not flagged and is valid
    }
    return somethingElse
  • Anonymous
    November 15, 2004
    The comment has been removed
  • Anonymous
    November 15, 2004
    Ah.. I forgot to mention: IF fallthrough would have been an option for switch then my analogy breaks.
  • Anonymous
    November 15, 2004
    The C# team had their freedom to define whatever a switch should mean. So stating there is no default in a switch is somewhat wrong. They could define a switch to mean: select a block, run it and that's it. The case statement could be extended to accept multiple parameters, event ranges. The goto shouldn't be there; extract the common code to a method and call it.

    The switch would be more C#-ish this way:

    switch(n)
    {
    case(1)
    {
    //do case 1
    }
    case(2,3,4)
    {
    //you get the idea
    }
    default()
    {
    }
    } // end switch

    I still think that requiring a nop keyword is just stupid.
  • Anonymous
    November 15, 2004
    The comment has been removed
  • Anonymous
    November 15, 2004
    P.S> As for a future. If due to some mysterious reasons C# will decide to allow fall through or will disable it (without requering break statement) - then it will be good that we requere break statement currently. It will not cause any problems in future.

    Thanks
  • Anonymous
    November 15, 2004
    "Radu, you were able to express your opinion once and now started to repeat."

    Because, as your last post demonstrates, my position is still not clear.

    I like the way C# solved the problem, but I think it has more to do with interaction with other languages (as Eric Gunnerson said) than with some simple logical reason (as JayBaz suggested). If C# would have been designed from scratch in a lab with no concern about programmers comming from various backgrounds then I would have not have liked the chosen solution.

    "For example you have provided an example about void g(){} void f(){ return g(); } . Why this does not compile?"

    Because I wrote it at work where I don't have a C# compiler to test. I assumed (wrongly it appears) that C# is consistent with C++ :-P (and, btw, I was afraid you'll find a challenge :) ). Again, I'm still not sure that it is clear what I meant with this analogy so I'm tempted to repeat in another form, but I'll refrain because it seems to annoy you.

    "Overall - my opinion that we must specify as much as possible inside language and make it easy to read for everybody - not only for computer geeks"

    This is where we bitterly disagree. Computer geeks have a natural tendency (like mathematicians) to keep thing as un-ambiguous as possible. This is what makes this field so "sterile" for the majority, who, like it or not, "derive their intelectual pleasure partly from not exactly knowing what they are doing" (Dijkstra). I'm afraid that such an opinion: "make it easy for everybody to read" will mean in practice "let's have a portion of ambiguity to attract more people to programming". Instead, we should keep elegance (= simple and effective) as our ultimate purpose.

    "So – in summary – some kind of mysterious code savings or readability. What do you select?"

    Ha.. that makes me trust your brother's opinion who doesn't know how to program and to whom the problem was presented in such an impartial manner.


  • Anonymous
    November 15, 2004
    Radu: What do you propose to do with current switch/break statement ?
    Can you post a summary of your suggestions ?

    P.S> If you will read first page of C# standart - you will find "Source code portability is very important, as is programmer portability, especially for those programmers already familiar with C and C++."

    "useless" break statement does add some kind of portability. While useless return; at void() does nothing. Here is a difference.
  • Anonymous
    November 16, 2004
    The comment has been removed
  • Anonymous
    November 16, 2004
    "What if we eliminate C++ programmers from the picture?" I've already posted a reference to C# standart that C++ programmers were taken in considerations and it was one of first design goals.
    If forget about C++ compatibility - I preffer Microsoft invested in functional languages.

    As for text-order selections - non-sence. This will result in switch reduced to lineriar sequence of "if/else" statements - and this will render "switch" statement useless.
    Changing order of statements must not result in logic change. You can possibly allow some cases to be selected randomly in this situation (just like BinarySearch does on non-sorted items).

    Original idea of switch must be performance - O(1) or O(log N) (where N is fictional number of if/else statements used).
    Readability still apply - but I put it on second place.

    Switch on regex is a cool idea.
    Actualy this is possible to compile a regex as composite of possibly statements - and this can provide performance benefits. Instead of executing RegexRunner for each statement - it will be executed only once.

    Thanks for your long reply.
    Why you did not post it in your blog ?
  • Anonymous
    November 16, 2004
    "As for text-order selections - non-sence. [...] and this will render "switch" statement useless."

    Not so. Pattern matching in functional languages works this way and is very much used. But I agree that it would be nice to have a better solution: "Changing order of statements must not result in logic change".

    "Why you did not post it in your blog ?"

    I had to choose between being suspected of poluting jaybaz's blog and trying to steer attention to my own site. I chose the first option as less intrusive :)
  • Anonymous
    November 17, 2004
    Pollute, pollute!

    :-)
  • Anonymous
    December 07, 2004
    The comment has been removed