38

Often when I hear about the switch statement, its put off as a way to replace long if...else chains. But it seems that when I use the switch statement I'm writing more code that I would be just writing if...else. You also have other issues like keeping all variables for all calls in the same scope.

Here's some code that represents the flow I normally write (thanks to diam)

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

if (which == 0) {
    comment = "You look so much better than usual.";
} else if (which == 1) {
    comment = "Your work is up to its usual standards.";
} else if (which == 2) {
    comment = "You're quite competent for so little experience.";
} else {
    comment = "Oops -- something is wrong with this code.";
}

Then they want me to replace that with this:

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

switch (which) {
    case 0:  
             comment = "You look so much better than usual.";
    break;
    case 1:  
             comment = "Your work is up to its usual standards.";
    break;
    case 2:  
             comment = "You're quite competent for so little experience.";
    break;
    default: 
             comment = "Oops -- something is wrong with this code.";
}

Seems like a lot more code in a much more awkward syntax. But is there really an advantage to using the switch statement?

TheLQ
  • 13,478
  • 7
  • 55
  • 87
  • Ugh. Yeah, that's certainly bulkier, but only in the C family, because its syntax for case statements is so ugly. – Mason Wheeler Oct 30 '10 at 21:23
  • 5
    This sort of thing has been discussed a lot on stackoverflow: - http://stackoverflow.com/questions/449273/why-the-switch-statement-and-not-if-else - http://stackoverflow.com/questions/767821/is-else-if-faster-than-switch-case - http://stackoverflow.com/questions/97987/switch-vs-if-else – Yevgeniy Brikman Oct 30 '10 at 22:48
  • 2
    You should avoid both whenever possible. It's much better to create a data structure and do a lookup, even if the lookup target is a function or class. – kevin cline Jan 03 '12 at 04:03
  • switch is faster, at least in .net. I don't know about Java. – Knerd Mar 25 '14 at 17:44
  • Can be refactored to a dictionary of cases and methods and one "if" – Pavel Yermalovich Aug 03 '15 at 11:21

10 Answers10

62

For this particular situation, it seems to me that both if and case are poor choices. I'd use a simple array:

String comments[] = {
    "You look so much better than usual.",
    "Your work is up to its usual standards.",
    "You're quite competent for so little experience."
};

String comment = comments[(int)(Math.random() * 3)];

As a side note, you should generally compute the multiplier based on the size of the array rather than hard-coding the 3.

As to when you would use a case/switch, the difference from a cascade of if statements (or at least one major difference) is that switch can semi-automatically optimize based on the number and density of values, whereas a cascade of if statements leaves the compiler with little choice but to generate code as you've written it, testing one value after another until it finds a match. With only three real cases, that's hardly a concern, but with a sufficient number it can/could be significant.

Jerry Coffin
  • 44,385
  • 5
  • 89
  • 162
  • That example was only an example BTW. Didn't know though that the compiler can optimize like that – TheLQ Oct 30 '10 at 21:29
  • @TheLQ - it depends on the language and the compiler of course. But yes, this is a simple optimization to perform, and pretty much essential. – Stephen C Oct 31 '10 at 00:38
  • Although this code is much much better (readability, maintainability, 'performance'), it doesn't handle the 'default' case.. in this code, you'd get an array bounds exception.. to complete the picture, what do you suggest? – JBRWilkinson Nov 01 '10 at 19:17
  • 6
    @JBRWilkinson. In this case, the out of bounds value is only possible via a compiler bug, which I'm disinclined to spend much time on (a bug in my code to test the result is about as likely as in the generating code). In a situation where an out of bounds value was a real concern (e.g., the index was being received from other code) I'd just check the bounds first, and use it as an index only after the check. – Jerry Coffin Nov 01 '10 at 19:23
  • 4
    I think this answer is very specific about the example, while the question was more generic than that... – Khelben Nov 02 '10 at 16:06
  • 5
    @Khelben: it sounds to me like you didn't bother reading the whole answer. The last paragraph addresses the wider issues. There is a problem though: I find *very few* situations in which I consider *either* a `case` statement or a cascade of `if` statements suitable. Most of the time, they're a (mediocre) substitute for some sort of map/array type of thing, and you're better off using one of the latter directly. – Jerry Coffin Nov 02 '10 at 17:20
  • I do not see how building an array of string results can be faster than 2 int comparisons. – Titou Sep 27 '16 at 14:13
  • 1
    @Titou: unless the compiler is utterly braindead, the array is going to be built once at compile time, and after that you're just using a static structure. For example, if you were doing this in C or C++, you'd want to make that a `static const` array, to assure that it always existed (but no language was given in the question, so I tried not to assume one in the answer either). – Jerry Coffin Sep 27 '16 at 14:48
  • @Jeremy Coffin: In a lazy evaluation scheme, the table would be built only if called... and possibly only required elements. However I agree that almost all compilers will work as you describe. – Titou Oct 26 '16 at 16:00
24

The problem with the if...else if... chain is that when I come along to read it, I have to look at every single if condition to understand what the program is doing. For example, you might have something like this:

if (a == 1) {
    // stuff
} else if (a == 2) {
    // stuff
} else if (a == 3) {
    // stuff
} else if (b == 1) {
    // stuff
} else if (b == 2) {
    // stuff
}

(obviously, for a small number of statements like this, it's not so bad)

I'd have no way of knowing that you changed condition variable half-way through without reading every single statement. However, because a switch limits you to a single condition variable only, I can see at a glance what's happening.

At the end of the day, though, I'd prefer neither switch or a chain of if...else if. Often a better solution is some kind of jump table or dictionary for cases like in the original question, or polymorphism (if your language supports that). It's not always possible, of course, but I'd look for a solution that avoids switch as a first step...

Dean Harding
  • 19,871
  • 3
  • 51
  • 70
  • 4
    polymorphism has the disadvantage of fragmenting the code, making it harder to understand as compared to be in a single location. Hence you may hesitate somewhat before changing into that. –  Jan 03 '12 at 10:34
  • Why is a jump table / dictionary better than a switch ? – Titou Sep 27 '16 at 14:22
15
switch (which) {
  case 0: comment = "String 1"; break;
  case 1: comment = "String 2"; break;
  case 2: comment = "String 3"; break;
  default: comment = "Oops"; break;
}

The above way of writing this type of switch case is fairly common. The reason why you felt the switch case if bulkier is because your body was only one line and with a switch case you also needed the break statement. So the switch case had twice the body size of if else. With more substantial code, the break statement will not add much to the body. For single line body, it is a common practice to write the code in the same line as the case statement.

As others have already mentioned, a switch case makes the intent more clear, you want to make a decision based on the value of a single variable/expression. My comments are purely from a readability point of view and not performance based.

aufather
  • 4,449
  • 2
  • 26
  • 24
8

In this case the switch statement more clearly matches the intent of the code: pick an action to take based on a single value.

The if statements on the other hand are much harder to read - you have to look at all of them to be sure what's going on. To me it's less code (even if the character count may be slightly higher) as there's less to mentally parse.

FinnNk
  • 5,799
  • 3
  • 28
  • 32
8

I agree with Jerry that an array of strings is better for this particular case, but that in general it's better to use a switch/case statement than a chain of elseifs. It's easier to read, and sometimes the compiler can do a better job of optimizing that way, but there's another benefit as well: it's a heck of a lot easier to debug.

When you hit that switch, you only have to step one time to end up on the right branch, instead of carefully stepping over several if statements one at a time, and possibly hitting the key too quickly and stepping past it and missing something and having to start over.

Mason Wheeler
  • 82,151
  • 24
  • 234
  • 309
3

I generally don't like either approach. Long switch or if statements just beg to be refactored to an object oriented abstraction (however your example I would classify as short, not long).

I would personally wrap that kind of code into a separate helper method.

private string GetInsult()
{
    int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

    switch (which) {
        case 0: return "You look so much better than usual.";
        case 1: return "Your work is up to its usual standards.";
        case 2: return "You're quite competent for so little experience.";
        default: return "Oops -- something is wrong with this code.";
    }
}

public void Foo()
{
    string comment = GetInsult();
    Print(comment);
}

Placing the switch in a separate method allows you to place return statements directly inside the switch statement (at least in c#), eliminating the need for break statements either, making the code much easier to read.

And this is imho much nicer than the if/else if/else if approach.

Pete
  • 8,916
  • 3
  • 41
  • 53
  • 3
    I personally hate the "put it in another method because it looks ugly" way to solve things. Clutters method list and looks worse IMHO. I would only do this if A) the code is duplicated somewhere or B) Could be useful elsewhere – TheLQ Jan 03 '12 at 16:11
  • 1
    what method list? and why is your method list being cluttered worse than your code being cluttered? I thought we moved past the "keep everything in one single method so you can see everything at once" age – sara Jun 01 '16 at 18:04
  • @TheLQ I agree with you in general, but in this very case the "comment=" is indeed factored by Pete's proposal. – Titou Sep 27 '16 at 14:35
3

I prefer switch in those kind of cases, it matches much better the point of the code, execute a different statement for each different input value. The if..else acts more like a "trick" to achieve the same effect.

switch statements are also cleaner, it's easy to have a typo hidden in all those ==

Also, for big blocks in C, switch is faster.

else..if can be more appropriate when you have something like ranges (between 1 and 100, do this, between 100 and 200 do that), or in C, when you try to make switch with elements like strings (that is possible in other languages). Which is a same.

I tend to use a lot of switches when I program in C.

Khelben
  • 1,339
  • 1
  • 8
  • 8
2

Pick something that is efficient, terse, and then document not just what you've done, but why.

Code can be revisited, and not always by its original author.

There are times when you might deliberately choose one implementation over another because you're forward-thinking about code that doesn't exist.

0

One of the things that makes the C/C# style switch particularly annoying is the insistence on the case value being literals. One nice thing about VB/VB.NET is that select/case allows each case to be any boolean expression. That is convenient. Insofar as a series of mutually exclusive boolean expressions is often helpful, a series of if/else ifs is more flexible, not to mention being more efficient to type and read.

Joel Brown
  • 2,388
  • 1
  • 19
  • 17
0

In python, there is no switch statement, because if/elif/else is nice:

a = 5

if a==1:
    print "do this"
elif a == 2:
    print "do that"
elif a == 3:
    print "do the other"
elif 3 < a < 9:
    print "do more"
elif 9 <= a < 15:
    print "do nothing"
else:
    print "say sorry"

Simple right?

Christopher Mahan
  • 3,404
  • 19
  • 22