views:

2110

answers:

15

This question in mainly pointed at C/C++, but I guess other languages are relevant as well.

I can't understand why is switch/case still being used instead of if/else if. It seems to me much like using goto's, and results in the same sort of messy code, while the same results could be acheived with if/else if's in a much more organized manner.

Still, I see these blocks around quite often. A common place to find them is near a message-loop (WndProc...), whereas these are among the places when they raise the heaviest havoc: variables are shared along the entire block, even when not propriate (and can't be initialized inside it). Extra attention has to be put on not dropping break's, and so on...

Personally, I avoid using them, and I wonder wether I'm missing something?

Are they more efficient than if/else's? Are they carried on by tradition?

A: 

Pretty sure they compile to the same things as If/ElseIf, but I find the Switch/Case easier to read when there are more than 2 or 3 "elses".

Bill
Which select are you talking about? There is no such thing in C.
qrdl
I think the original question was phrased in terms of Select/Case and bill just didn't correct him. +1 compensation point. (by the way, that nets you 8 points, not bad for an error)
Bill K
Sorry, I am a VB/SQL guy, so Select/Case is the right syntax for me. As for how it compiles, I think I am right for VB6, but I expect VB.Net compiles more like C++.
Bill
I tried this code, using select/case in C++ and it didn't work. I think select is broken.
Beska
Since the question (now) refers to switch/case and C/C++, I've edited the answer. Feel free to edit back.
Max Lybbert
+4  A: 

Switch/case is usually optimized more efficiently than if/else if/else, but is occasionally (depending on language and compiler) translated to simple if/else if/else statements.

I personally think switch statements makes code more readable than a bunch of if statements; provided that you follow a few simple rules. Rules you should probably follow even for your if/else if/else situations, but that's again my opinion.

Those rules:

  • Never, ever, have more than one line on your switch block. Call a method or function and do your work there.
  • Always check for break/ case fallthrough.
  • Bubble up exceptions.
Randolpho
switches are _not_ usually translated to if-else sequences. See qrdl's answer. :-)
Chris Jester-Young
Hmm... on second read, I'm wrong. I thought I had written my first sentence in a different way than it actually is. My bad.
Randolpho
+73  A: 

Summarising my initial post and comments - there are several advantages of switch statement over if/else statement:

  1. Cleaner code. Code with multiple chained if/else if ... looks messy and is difficult to maintain - switch gives cleaner structure.

  2. Performance. For dense case values compiler generates jump table, for sparse - binary search or series of if/else, so in worst case switch is as fast as if/else, but typically faster. Although some compilers can similarly optimise if/else.

  3. Test order doesn't matter. To speed up series of if/else tests one needs to put more likely cases first. With switch/case programmer doesn't need to think about this.

  4. Default can be anywhere. With if/else default case must be at the very end - after last else. In switch - default can be anywhere, wherever programmer finds it more appropriate.

  5. Common code. If you need to execute common code for several cases, you may omit break and the execution will "fall through" - something you cannot achieve with if/else. (There is a good practice to place a special comment /* FALLTHROUGH */ for such cases - lint recognises it and doesn't complain, without this comment it does complain as it is common error to forgot break).

Thanks to all commenters.

qrdl
+1 on mention of jump table (for dense values). Or a binary search, if the values are sparse. :-)
Chris Jester-Young
Ofcourse, I meant switch/case. Thanks for the correction.
OB OB
+1,. also, order doesn't matter in switch, which makes it nice in some cases, like switch(x) { default: assert(0 other-cases-here };
Johannes Schaub - litb
@litb Very good point!
qrdl
@litb: I'm preety sure you're wrong: switch(a){case 1: printf("1"); case 2: printf("2"); break;} would print "12" for a==1, so order does matter.
OB OB
@OB OB: Order doesn't matter if "best practice" of no-fallthrough is used.
Chris Jester-Young
Order matters if you're not breaking after every case. But that type of code should be used sparingly. It is not what most programmers expect
jkerian
@OB In case of if/else you need to place more likely cases first to minimise number of tests performed. In case of switch you don't need to worry about that.
qrdl
This would take a really messed up compiler to still be true (It may be true, but someone might want to check the assembly after compiling with O4). My guess is that the primary reason is that people still THINK it performs better.
Bill K
@Bill K: I'm not sure why you think it would require a messed up compiler to have an optimization that's been around since at least the 80s. It should be mentioned that most switch/case blocks are unable to be optimized in that fashion, but some can be. The biggest reason for sticking with switch/case is that it is extremely clear syntax... follow one of x paths, determined strictly by the value of variable Y.
jkerian
I think what Bill K meant was that a good compiler is likely to optimize if/else if/else the same way as switch/case.
OB OB
@OB OB, i'm sorry. What i meant was the order of default and other labels, only with regard to jumping to the code. While with if/else, the else have to be at the end, with switch, you can put the default at the beginning. It's right that once switch jumps to one label, control will flow without breaking, of course :)
Johannes Schaub - litb
How compiler could possible know which test is more likely? Let's say I'm testing characters read from file - I know that EOF is least likely case but compiler doesn't know that.
qrdl
@qrdl: The point is: aren't today's compilers samrt enough to covert if/else if/else to swtich/case, when optimization benefits from it?
OB OB
@qrdl: Actually, on your point about the programmer knowing the "more likely path", some compilers (e.g., gcc) allow you to specify that, and it will provide branch prediction hints to the CPU. :-P
Chris Jester-Young
@Bill K: I just tested it with GCC, and even with -O3, it doesn't optimize the if/else chain into a jump table, whereas with a switch it does even without optimizations on. Other compilers' mileage may vary.
Greg Rogers
Heck, I'm not surprised. Up to -O3 java is pretty much as fast as C. -O4 it tends to blow java away. Also, you could certainly be right about what code is generated, but it's probably compiler dependent. When I worked with MSC version 6, it was already known to have optimizations that hadn't existed before. I'm not sure you'll get the same stuff out of other compilers.
Bill K
A: 

Switch statements can be optimized for speed, but can take up more memory if the case values are spread out over large numbers of values.

if/else are generally slow, as each value needs to be checked.

SP
+19  A: 

Well, one reason is clarity....

if you have a switch/case, then the expression can't change.... i.e.

switch (foo[bar][baz]) {
case 'a':
    ...
    break;
case 'b': 
    ...
    break;
}

whereas with if/else, if you write by mistake (or intent):

if (foo[bar][baz] == 'a') {
    ....
}
else if (foo[bar][baz+1] == 'b') {
    ....
}

people reading your code will wonder "were the foo expressions supposed to be the same", or "why are they different"?

Eric H.
+6  A: 

It might also depend on your language -- For example, some languages switch only works with numeric types, so it saves you some typing when you're working with an enumerated value, numeric constants... etc...

If (day == DAYOFWEEK_MONDAY) {
    //...
}
else if (day == DAYOFWEEK_TUESDAY) {
    //...
}
//etc...

Or slightly easier to read...

switch (day) {
    case DAYOFWEEK_MONDAY :
        //...
    case DAYOFWEEK_TUESDAY :
        //...
    //etc...
}
Hugoware
+9  A: 

If there are lots of cases, the switch statement seems cleaner.

It's also nice when you have multiple values for which you want the same behavior - just using multiple "case" statements that fall through to a single implementation is much easier to read than a if( this || that || someotherthing || ... )

Eric Petroelje
+12  A: 

please remember that case/select provides additional flexibility:

  • condition is evaluated once
  • is flexible enough to build things like the Duff's device
  • fallthrough (aka case without break)

as well as it executes much faster (via jump/lookup table) * historically

dfa
Are you assuming that compiler designers can't figure out how to convert a series of if/elses into a jump table, or have you actually checked this with a compiler from the last 10 years?
Bill K
you are right, of course. Let me explain that storically switch is far much faster than if/else, right?
dfa
Any compiler worth their salt will evaluate the condition only once in an if/else chain. And it will generate an similar jump table. (Provided you've coded the if/else chain much like the switch/case, e.g. not altering the condition etc,)
nos
what about if the condition contains a side effect?
dfa
If it can't be done as a switch statement, it might only optimize the ones that can. Typically the compiler is much smarter than programmers give it credit for.
Bill K
+2  A: 

Clarity. As I said here, a clue that else if is problematic is

the frequency with which ELSE IF is used in a far more constrained way than is allowed by the syntax. It is a sledgehammer of flexibility, permitting entirely unrelated conditions to be tested. But it is routinely used to swat the flies of CASE, comparing the same expression with alternate values...

This reduces the readability of the code. Since the structure permits a universe of conditional complexity, the reader needs to keep more possibilities in mind when parsing ELSE IF than when parsing CASE.

Carl Manaster
+3  A: 

Actually a switch statement implies that you are working of something that is more or less an enum which gives you an instant clue what's going on.

That said, a switch on an enum in any OO language could probably be coded better--but a series of if/else's on the same value would imply the same probability of a poor design.

Bill K
A: 

A Smalltalker might reject both switch and if-then-else's and might write something like:-

shortToLongDaysMap := Dictionary new.

shortToLongDaysMap
at: 'Mon'     put:  'Monday';
at: 'Tue'     put:  'Tuesday';
at: 'Wed'     put:  'Wednesday'
etc etc.

longForm := shortToLongDaysMap at: shortForm ifAbsent: [shortForm]

This is a trivial example but I hope you can see how this technique scales for large numbers of cases.

Note the second argument to at:IfAbsent: is similar to the default clause of a case statement.

KHWP
+6  A: 

Also remember that switch statements allows the flow of control to continue, which allows you to nicely combine conditions while allowing you to add additional code for certain conditions, such as in the following piece of code:

switch (dayOfWeek)
{
    case MONDAY:
        garfieldUnhappy = true;
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
       weekDay = true;
       break;
    case SATURDAY:
       weekendJustStarted = true;
    case SUNDAY:
       weekendDay = true;
       break;
}

Using if/else statements here instead would not be anywhere as nice.

if (dayOfWeek == MONDAY)
{
    garfieldUnhappy = true;
}
if (dayOfWeek == SATURDAY)
{
    weekendJustStarted = true;
}
if (dayOfWeek == MONDAY || dayOfWeek == TUESDAY || dayOfWeek == WEDNESDAY
    || dayOfWeek == THURSDAY || dayOfWeek == FRIDAY)
{
    weekDay = true;
}
else if (dayOfWeek == SATURDAY || dayOfWeek == SUNDAY)
{
    weekendDay = true;
}
Joseph Paterson
+3  A: 

addressing the concern that everything inside the switch has equivalent scope, you can always throw your case logic into another { } block, like so ..

switch( thing ) {
    case ONETHING: {
        int x; // local to the case!
        ...
        }
        break;
    case ANOTHERTHING: {
        int x; // a different x than the other one
        }
        break;
}

.. now I'm not saying that's pretty. Just putting it out there as something that's possible if you absolutely have to isolate something in one case from another.

one other thought on the scope issue - it seems like a good practice to only put one switch inside a function, and not a lot else. Under those circumstances, variable scope isn't as much of a concern, since that way you're generally only dealing with one case of execution on any given invocation of the function.

ok, one last thought on switches: if a function contains more than a couple of switches, it's probably time to refactor your code. If a function contains nested switches, it's probably a clue to rethink your design a bit =)

JustJeff
A: 

switch case is mainly used to have the choice to made in the programming .This is not related the conditional statement as :

if your program only require the choice to make then why you use the if/else block and increase the programming effort plus it reduce the execution speed of the program .

sandy101
A: 

The main reason behind this is Maintainability and readability. Its easy to make code more readable and maintainable with Switch/case statement then if/else. Because you have many if/else then code become so much messy like nest and its very hard to maintain it.

And some how execution time is another reason.

Azhar