Search code examples
clanguage-design

Why was the switch statement designed to need a break?


Given a simple switch statement

switch (int)
{
    case 1 :
    {
        printf("1\n");
        break;
    }

    case 2 : 
    {
        printf("2\n");
    }

    case 3 : 
    {
        printf("3\n");
    }
}

The absence of a break statement in case 2, implies that execution will continue inside the code for case 3. This is not an accident; it was designed that way. Why was this decisions made? What benefit does this provide vs. having an automatic break semantic for the blocks? What was the rationale?


Solution

  • Many answers seem to focus on the ability to fall through as the reason for requiring the break statement.

    I believe it was simply a mistake, due largely because when C was designed there was not nearly as much experience with how these constructs would be used.

    Peter Van der Linden makes the case in his book "Expert C Programming":

    We analyzed the Sun C compiler sources to see how often the default fall through was used. The Sun ANSI C compiler front end has 244 switch statements, each of which has an average of seven cases. Fall through occurs in just 3% of all these cases.

    In other words, the normal switch behavior is wrong 97% of the time. It's not just in a compiler - on the contrary, where fall through was used in this analysis it was often for situations that occur more frequently in a compiler than in other software, for instance, when compiling operators that can have either one or two operands:

    switch (operator->num_of_operands) {
        case 2: process_operand( operator->operand_2);
                  /* FALLTHRU */
    
        case 1: process_operand( operator->operand_1);
        break;
    }
    

    Case fall through is so widely recognized as a defect that there's even a special comment convention, shown above, that tells lint "this is really one of those 3% of cases where fall through was desired."

    I think it was a good idea for C# to require an explicit jump statement at the end of each case block (while still allowing multiple case labels to be stacked - as long as there's only a single block of statements). In C# you can still have one case fall through to another - you just have to make the fall thru explicit by jumping to the next case using a goto.

    It's too bad Java didn't take the opportunity to break from the C semantics.