14

When is it appropriate to use a fall-through (classic) switch statement? Is such usage recommended and encouraged or should it be avoided at all costs?

  • Not all languages allow fall-through on switch statements. – Oded Oct 25 '11 at 19:17
  • @Oded, edited, added "classic" word. Not all languages allow fall through, nevertheless I insist it is classic ) – shabunc Oct 25 '11 at 19:22
  • 3
    If you are talking about Duffs' device, that's one thing. – Oded Oct 25 '11 at 19:23
  • 6
    @Oded: That's the first thing most people think of, but that's hardly "appropriate." According to this, Duff himself said "This definitely provides an argument in the discussion whether switch should fall through by default, but I'm not sure if the argument is for or against it." – BlueRaja - Danny Pflughoeft Oct 26 '11 at 5:32
15

Here's an example where it would be useful.

public Collection<LogItems> GetAllLogItems(Level level) {
    Collection<LogItems> result = new Collection<LogItems>();
    switch (level) {
        // Note: fall through here is INTENTIONAL
        case All:
        case Info:
             result.Add(GetItemsForLevel(Info));
        case Warning:
             result.Add(GetItemsForLevel(Warning));
        case Error:
             result.Add(GetItemsForLevel(Error));
        case Critical:
             result.Add(GetItemsForLevel(Critical));
        case None:
    }
    return result;
}

This sort of thing (where one case includes the other) is rather rare, I think, which is why some newer languages either don't allow fallover or require special syntax for it.

  • 13
    This example, while interesting, is lacking the requisite all-caps // INTENTIONAL FALL THROUGH HERE comment. – Russell Borogove Oct 26 '11 at 1:45
  • It's just as easy to write this code with falling through by having the GetItemsForLevel(Info) call invoke GetItemsForLevel(Warning) and so on. – Caleb Oct 26 '11 at 14:55
  • @RussellBorogove: Absolutely correct. – configurator Oct 26 '11 at 15:15
  • @Caleb: In this case, yes. But what if the calls were a little more complicated? It could get a bit hairy, while fall through makes it seem simple. I should note I'm not actually in favour of using fall through - I'm just saying it can be useful in certain situations. – configurator Oct 26 '11 at 15:17
  • Not the best example. There is an ordering of the warning levels. By defining that ordering, this method reduces to a single line of code filtering items when the item level is at least equal to the desired level. – kevin cline Oct 3 '16 at 18:11
8

I use them when certain functionality has to be applied for more than one value. For example, say you had an object with a property called operationCode. If the code equals 1, 2, 3 or 4, you want to startOperationX(). If it's 5 or 6, you want to startOperationY() and 7 you startOperationZ(). Why have 7 complete cases with functionality and breaks when you can use fall-throughs?

I think it's completely valid in certain situations, especially if it avoids 100 if-else statements. =)

  • 4
    What you're describing is a switch with multiple cases tied to the same code. That's different than a fall-through, where execution of one case continues into the next one because of the lack of a break between them. – Blrfl Oct 25 '11 at 20:47
  • 3
    It doesn't really matter, the fall-through is just the lack of a break statement so it "falls through" to the next case. – Yatrix Oct 25 '11 at 21:02
  • I'd re-word the scenario in your answer to reflect that. – Blrfl Oct 25 '11 at 21:11
  • 2
    @Yatrix: I disagree. It is much different to have consecutive cases all executing the exact same block of code than it is to omit a break. One is routine, the other far from it (ime) - and the potential for misreading and unintended control flow is much greater. – quentin-starin Oct 25 '11 at 23:33
  • 3
    @qes yes, it's different, but they are both fall-throughs. He asked when/if it'd be appropriate. I gave an example of when it would. It wasn't meant to be an all-inclusive example. Depending on the language, having statements before a fall-through may not work. I don't think it will with C# stackoverflow.com/questions/174155/… – Yatrix Oct 26 '11 at 13:15
8

I've used them occasionally, I think its always appropriate usage - but only when included with the appropriate comment.

7

Fall-through cases are perfectly fine. I often find that an enumeration is used in lots of places, and that when you don't need to differentiate some cases it is easier to use fall-through logic.

For example (note the explanatory comments):

public boolean isAvailable(Server server, HealthStatus health) {
  switch(health) {
    // Equivalent positive cases
    case HEALTHY:
    case UNDER_LOAD:
      return true;

    // Equivalent negative cases
    case FAULT_REPORTED:
    case UNKNOWN:
    case CANNOT_COMMUNICATE:
      return false;

    // Unknown enumeration!
    default:
      LOG.warn("Unknown enumeration " + health);
      return false;
  }
}

I find this kind of use perfectly acceptable.

  • Note that there is a big difference between case X: case Y: doSomething() and case X: doSomething(); case Y: doAnotherThing(). In the first, the intention is quite explicit, while in the second, the fall through may be intentional or not. In my experience, the first example never triggers any warnings in compilers/code analyzers, while the second one does. Personally, I would only call the second example "fall through" - not sure about an "official" definition, though. – Jens Bannmann Jun 12 '18 at 6:36
6

It depends on:

  • your personal preference
  • your employer's coding standards
  • the amount of risk involved

The two main problems associated with letting one case fall through to the next are:

  1. It makes your code dependent on the order of the case statements. That's not the case if you never fall through, and it adds a degree of complexity that's often unwelcome.

  2. It's not obvious that the code for one case includes the code for one or more subsequent cases.

Some places explicitly prohibit falling through. If you don't work at such a place, and if you're comfortable with the practice, and if breaking the code in question won't cause any real suffering, then it might not be the worst thing in the world. If you do it, though, be sure to put an attention-grabbing comment nearby to warn those who come later (including the future you).

4

Here's a quick (admittedly incomplete (no special handling of leap year)) example of fall-through making my life simpler:

function get_julian_day (date) {
    int utc_date = date.getUTCDate();
    int utc_month = date.getUTCMonth();

    int julian_day = 0;

    switch (utc_month) {
        case 11: julian_day += 30;
        case 10: julian_day += 31;
        case 9:  julian_day += 30;
        case 8:  julian_day += 31;
        case 7:  julian_day += 31;
        case 6:  julian_day += 30;
        case 5:  julian_day += 31;
        case 4:  julian_day += 30;
        case 3:  julian_day += 31;
        case 2:  julian_day += 28;
        case 1:  julian_day += 31;
        default: break;
    }

    return julian_day + utc_date;
}
  • 5
    While this is kind of clever, the time you save from doing this is going to be far outweighed by the time it takes for other people to figure out what this does. Also, you could get better performance by removing the fall-through aspect i.e. 31+28+31 is always 90. If you are going to do this, you might as well just put the totals in the cases since there's only 11 to consider. – JimmyJames Oct 3 '16 at 17:23
  • You're right, my example is definitely contrived :) I will say, however, it's easier to spot a hidden bug when the number of days are spelled out like this instead of pre-computing all the cumulative days for each case of the switch. – AaronDanielson Oct 3 '16 at 18:01
  • 2
    I'll grant you that but doing that in a constant declaration would be preferable e.g. FEB_START = 31; MAR_START = FEB_START + 28; etc. not sure what language this is but in many, it would be computed at compile time. The bigger issue here is that it's a little obtuse. Not so much that it's a bad idea, just atypical. Unless there is a really big benefit, it's generally better to stick with common idioms. – JimmyJames Oct 3 '16 at 18:17
  • 1
    Excellent alternative, using constants for start days on this example. Anyway, the point here is that a cumulative sum is a great use for a switch-case fall-through. I agree 100% on using common idioms, but the nature of this question is venturing into the more esoteric features where common idioms are hard to come by. – AaronDanielson Oct 3 '16 at 18:37
3

If I feel a need to go from one case to another (rare, admittedly), I prefer to be very explicit and goto case, of course, that assumes your language supports it.

Because falling thru is so uncommon, and very easy to overlook while reading code, I feel it is appropriate to be explicit - and a goto, even if it's to a case, should stand out like a sore thumb.

It also helps avoid bugs that may occur when case statements are reordered.

protected by gnat Oct 3 '16 at 18:53

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.