Mar 15

Why C Switch Statements Should go the way of the GOTO

Category: C, C#, Programming, Ruby

The venerable C switch statement keeps showing up in other languages presumably because the people who write new languages are familiar with C and don’t really think about it.

What is it


So the C-style switch statement is an efficient way of executing code based on an index. For efficiency reasons the index has to be an integer and the values mapped to code have to be constants:

switch(someint){
case 0:
    //do something
    break;
case 1:
    //do something 
    break;
default:
    //error?
    break;
}

Apart from having some syntactic benefit, switch statements can be compiled very efficiently (by using the case value as a jump offset).

The switch statement also allows you to execute the same code for multiple values by allowing fall-through from one case statement to the next. If you omit the break then the execution falls through to the next case statement.

switch(someint){
case 0:
case 1:
    //do something for 0 or 1
    break;
default:
    //error?
    break;
}

Who Does It


Well at the very least:

  1. C
  2. C++
  3. Java
  4. D


Why I Hate Them


The main problem is the fall through:

switch(somevar){
case 1:
    do_something();
    do_something_else();
    for(i=0; i < 12; i++){
        //so on
    }
case 2:
    work_on_it();
default:
    do_this_for_everyone();
}

So why is this bad?

  1. Counter to this particular example, fall through is not the common case, it is the exception. Extra code should be required for the exception and not for the common case.
  2. If you wrote this code, you may have meant to put a break in and forgot.
  3. If you are reading this code you may not notice the breaks are missing because they are usually there. Even if you do you now have to wonder about question #2.
  4. If you maintain this code you may change something about a case that means a break would be appropriate without realizing you have to add the break. This will not be obvious and may not even show up as a bug until much later.


How to fix it


Basically the way to fix this is to require the coder to explicitly do something to indicate they really want to do a fallthrough.

C#


C# does it better. In C# you have to explicitly state the fall-through using a special version of GOTO (OK I know I said I hate goto as well, but this is a good way to use it) as follows:

switch(somevar){
case 1:
    do_something();
    do_something_else();
    for(i=0; i < 12; i++){
        //so on
    }
    goto case 2;
case 2:
    work_on_it();
    goto case default;
default:
    do_this_for_everyone();
}

Now there is no question as to the intent of the code. Furthermore you can’t accidentally intend fall through and not get it because leaving off a break or a goto is a compile time error. Why don’t all languages do this instead of slavishly following the C style nonsense?


Ruby


Of course the other thing you can do is just get rid of fall-through completely:

case foo
    when 1    then puts "Foo is equal to 1"
    when 2..9 then puts "Foo is between 2 and 9"
    when 10   then puts "Foo is equal to 10"
end

The Author

Michael Smit is a software engineer in Seattle, Washington who works for amazon

2 comments

2 Comments so far

  1. mike L. March 19th, 2008 12:36 pm

    Come on! switch/break is the lazy mans if/elseif statement. don’t forget perl and php. Its also good for building strings…

  2. mike March 19th, 2008 12:44 pm

    Perhaps I should have said “C-style” switch statements. I have no problem with the idea of a switch statement, I just think C did it in a way that encourages programmer error and there isn’t any good reason to keep copying that style into other languages.