views:

1024

answers:

11

For as long as I can remember I have avoided using switch statement fallthrough. Actually, I can't remember it ever entering my consciousness as a possible way to do things as it was drilled into my head early on that it was nothing more than a bug in the switch statement. However, today I ran across some code that uses it by design, which got me immediately wondering what everyone in the community thinks about switch statement fallthrough.

Is it something that a programming language should explicitly not allow (like C# does, though it supplies a workaround) or is it a feature of any language that is powerful enough to leave in the programmer's hands?

Edit: I wasn't specific enough to what I meant by fallthrough. I use this type a lot:

    switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

However, I'm concerned about something like this.

   switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something but fall through to the other cases 
            // after doing it.
        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

This way whenever the case is 0, 1 it will do everything in the switch statement. I've seen this by design and I just don't know if I agree that switch statements should be used this way. I think the first code example is a very useful and safe. The second seems kind of dangerous.

+12  A: 

Fallthrough is really a handy thing, depending on what you're doing. Consider this neat and understandable way to arrange options:

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // do something
    break;
  case 'd':
  case 'e':
    // do something else
    break;
}

Imagine doing this with if/else. It would be a mess.

Lucas Oman
I find this type of fallthrough to be very helpful
Mitchel Sellers
+2  A: 

Powerful and dangerous. The biggest problem with fall-through is that it's not explicit. For example, if you come across frequently-edited code that has a switch with fall-throughs, how do you know that's intentional and not a bug?

Anywhere I use it, I ensure that it's properly commented:

switch($var) {
    case 'first':
        // fall-through
    case 'second':
        i++;
        break;
 }
Dan Hulton
The intent is obvious if there is no code for case 'first'. If you code in there, and also want to run the code for case 'second', then the comment is important. But I'd avoid that scenario anyway.
Joel Coehoorn
@Joel - I agree completely. In my shop, we've had people put in fallthough comments in such cases, and I think it reduces readability. If there's code there, though, put in the fallthrough comment.
Fred Larson
+6  A: 

Have you heard of Duff's device? This is a great example of using switch fallthrough.

It's a feature that can be used and it can be abused, like almost all language features.

ΤΖΩΤΖΙΟΥ
Learn something new every day - thanks! I do feel for the poor devs that go though such contortions though.
fatcat1111
Wow, that is quite something to wrap your brain around.
Fostah
Note Duff's quoted comment in that article: "This code forms some sort of argument in that debate, but I'm not sure whether it's for or against."
therefromhere
A: 

In some instances, using fall-throughs is an act of laziness on the part of the programmer - they could use a series of || statements, for example, but instead use a series of 'catch-all' switch cases.

That being said, I've found them to be especially helpful when I know that eventually I'm going to need the options anyway (for example in a menu response), but have not yet implemented all the choices. Likewise, if you're doing a fall-through for both 'a' and 'A', I find it substantially cleaner to use the switch fall-through than a compound if statement.

It's probably a matter of style and how the programmers think, but I'm not generally fond of removing components of a language in the name of 'safety' - which is why I tend towards C and its variants/descendants more than, say, Java. I like being able to monkey-around with pointers and the like, even when I have no "reason" to.

warren
+1  A: 

As with anything: if used with care, it can be an elegant tool.

However, i think the drawbacks more than justify NOT to use it, and finally not to allow it anymore (C#). Among the problems are:

  • it's easy to "forget" a break
  • it's not always obvious for code maintainers THAT an omitted break was intentional

good use of a switch/case fallthrough:

switch (x)
{
case 1:
case 2:
case 3:
 do something
 break;
}

BAAAAAD use of a switch/case fallthrough:

switch (x)
{
case 1:
    some code
case 2:
    some more code
case 3:
    even more code
    break;
}

This can be rewritten using if/else constructs with no loss at all in my opinion.

My final word: stay away from fall-through case labels as in the BAD example, unless you are maintaining legacy code where this style is used and well understood.

steffenj
You can re-write most language constructs using if() and goto... that doesn't justify abandoning an explicit construct though.
Shog9
I know but switch/case constructs that explicitly use the "case 1: some code case 2: some more code case 3: final code break;" can and should be rewritten using if/else if (my opinion).
steffenj
+7  A: 

It's a two-edged sword. Sometimes very useful, often dangerous.

When is it good? When you want 10 cases all processed the same way...

switch (c) {
  case 1:
  case 2:
            ... do some of the work ...
            /* FALLTHROUGH */
  case 17:
            ... do something ...
            break;
  case 5:
  case 43:
            ... do something else ...
            break;
}

The one rule I like is that if you ever do anything fancy where you exclude the break, you need a clear comment /* FALLTHROUGH */ to indicate that was your intention.

John M
+1! I agree that it is occasionally the right answer, and I DOUBLY agree that when it's by design, it should be commented. (In a code review, I'd MAKE the other developer comment a by-design non-empty fall-through. Not that it happens; we're a C# shop where that's not supported :)
John Rudy
I myself use a /* FALL THROUGH */ comment in my code where appropriate. =]
strager
If you PC-Lint, you have to insert /*-fallthrough*/, otherwise it complains.
Steve Melnikoff
+1  A: 

I don't like my switch statements to fall through - it's far too error prone and hard to read. The only exception is when multiple case statements all do exactly the same thing.

If there is some common code that multiple branches of a switch statement want to use, I extract that into a separate common function that can be called in any branch.

Matt Dillard
+9  A: 

It may depend on what you consider fallthrough. I'm ok with this sort of thing:

switch (value)
{
  case 0:
    result = ZERO_DIGIT;
    break;

  case 1:
  case 3:
  case 5:
  case 7:
  case 9:
     result = ODD_DIGIT;
     break;

  case 2:
  case 4:
  case 6:
  case 8:
     result = EVEN_DIGIT;
     break;
}

But if you have a case label followed by code that falls through to another case label, I'd pretty much always consider that evil. Perhaps moving the common code to a function and calling from both places would be a better idea.

And please note that I use the Marshall Cline definition of "evil"

Fred Larson
I agree with you: I don't think of your example as fallthrough, and if there's a case where I want to execute multiple blocks of code via fallthrough, there's probably a better way to do it.
Dave DuPlantis
+1 simply for that definition of "evil". I will borrow that, thanks ;-)
Joachim Sauer
I get your point and you are right, but your example is really bad. Nobody should test test digits like this. Scnr, your answer is right anyway.
Tim Büthe
+3  A: 

It can be very useful a few times, but in general, no-fallthrough is the desired behavior. Fallthrough should be allowed, but not implicit.

An example, to update old versions of some data:

switch (version) {
    case 1:
        // update some stuff
    case 2:
        // update more stuff
    case 3:
        // update even more stuff
    case 4:
        // and so on
}
A: 

fall thought should be used only when it is used as a jump table into a block of code. If there is any part of the code with an unconditional break before more cases, all the case groups should end that way. Anything else is "evil".

BCS
+2  A: 

I'd love a different syntax for fallbacks in switches, something like, errr..

switch(myParam)
{
  case 0 or 1 or 2:
    // do something;
    break;
  case 3 or 4:
    // do something else;
    break;
}

Note: This would already be possible with enums, if you declare all cases on your enum using flags right? Doesn't sound so bad either, the cases could (should?) very well be part of your enum already.

Maybe this would be a nice case (no pun intended) for a fluent interface using extension methods? Something like, errr...

int value = 10;
value.Switch()
  .Case(() => { /* do something; */ }, new {0, 1, 2})
  .Case(() => { /* do something else */ } new {3, 4})
  .Default(() => { /* do the default case; */ });

Although that's probably even less readable :P

Erik van Brakel
I like the first suggestion a lot. That reads very well and saves a few lines of code. The second took a minute to wrap my brain around but makes sense, but it does look primed to be a mess.
Fostah
Yeah, that's what I thought as well, it was just a random mind fart I put down, in an effort to find a different way to switch using existing language constructs.
Erik van Brakel