PDA

View Full Version : Switch vs If


Upchurch
29th January 2006, 03:18 PM
What is better: Switch statements or If...Else If statements? And why?

I've heard from various sources give conflicting reports about which is faster and which is better for handling data. Personally, having come from a symbolic logic background, if...else if statements come much more natural to me, but I don't want to not use switch statements simply because I'm used to something else.

Opinions?

JamesM
29th January 2006, 04:04 PM
In my completely unprofessional opinion, I would minimise the use of if-else or switch so that it didn't matter which I used over the small number of options I was using it for.

Whenever I have ended up with a very large chunk of if-else code, unless it was for something trivial like parsing options from a command line, I ended up either refactoring to the strategy (or state) pattern, or I ploughed on regardless, and then bitterly regretted my decision shortly thereafter.

That assumes you're using an OO language, of course.

JamesM
29th January 2006, 04:17 PM
I realise I haven't answered your question at all. Sorry. I think in C, C++ and Java, the compiler can do some optimisations depending on how similar the int values are in the switch statement.

I certainly wish my coding was so efficient that this sort of thing was the bottleneck...

El Greco
29th January 2006, 04:29 PM
There shouldn't make any difference, I guess the compiler will output the same instructions either way. Look at this (http://www.intel.com/cd/ids/developer/asmo-na/eng/66779.htm?prn=Y).

PixyMisa
29th January 2006, 05:50 PM
Well, as El Greco points out, processors only have conditional branch instructions, so a switch and an if-then will compile to roughly the same code.

Use whichever produces a cleaner and more readable program.

a_unique_person
29th January 2006, 06:08 PM
What is better: Switch statements or If...Else If statements? And why?

I've heard from various sources give conflicting reports about which is faster and which is better for handling data. Personally, having come from a symbolic logic background, if...else if statements come much more natural to me, but I don't want to not use switch statements simply because I'm used to something else.

Opinions?

I would not bother with what was faster unless there was a compelling hardware reason. Computers are here to work for us.

roger
29th January 2006, 06:57 PM
Well, as El Greco points out, processors only have conditional branch instructions, so a switch and an if-then will compile to roughly the same code.
Well, not necessarily. A compiler can convert a switch statement into an index address jump, making it effectively 1 operation to process the condition, as opposed to O(n/2) comparisons for if/else. With that said, I've rarely seen compilers generate that kind of code, though I have seen it. And of course, a really good optimizer could change the if/then into the equivelent if, gaining the same advantage.

More importantly, code your routine so it is readable as possible. Unless you are in a tight inner loop, the speed probably doesn't matter.

kevin
29th January 2006, 08:25 PM
If it's important to the speed of the program, model it both ways and use the fastest. It's rarely that important to a program though.

I teach (I also debug what others have written) a specialized language for a plotting program for CAD software (InterPlot pen table language if you're really interested) and I've found for beginning script writers that extensive use of else if almost always results in a logic error, or is very unreadable and hard to debug.

samples below (i think the language is easy enough for most people to see what is going on)


if ((level_name == 'contours') and (color == 2)) then
priority = 5
color = 'light gray'
else if (color == 3) then
priority = 10
color = 'dark gray'
endif


There is a logic flaw in the above from what most users intend. The else if will trigger for all elements of color 3 no matter what. Most users mean for it to trigger when level_name is contours AND the color is 3. This is a very common mistake for new users.

Here's I usually write this

if (level_name == 'contours') then
switch (color)
case 2 ?
priority = 5
color = 'light gray'
case 3 ?
priority = 10
color = 'dark gray'
endswitch
endif


You'll notice that when properly indented the switch statments tend to line up the comparisons, while with else if's they tend to fall in the middle of a lot of text making them harder to find. Also the code for what is happening in each situation is indented more and makes following what is going on much easier.

Generally when I recommend on technique over the other it almost never comes down to which is faster and always comes down to which is easier to read, understand and maintain.

It takes a lot of executions for a 1/5 of a second improvement in execution time to make up for a 4 hour debugging session.

Oh and languages that require a break to get out a switch case, i hate those.

PixyMisa
29th January 2006, 09:35 PM
I wrote a virtual machine for a language once (neither one ended up getting implemented, but them's the breaks). Lots of fun tweaking the inner loop where it issued the opcodes and seeing the code produced by various compilers.

I tried using an array of function pointers, and it was faster - on some platforms - but caused problems with special cases. I ended up just using one big switch statement and relying on the optimiser to do all the hard work.

kevin
29th January 2006, 09:43 PM
I tried using an array of function pointers, and it was faster - on some platforms - but caused problems with special cases. I ended up just using one big switch statement and relying on the optimiser to do all the hard work.

And in these days of frequent processor changes and software distribution by source (open or otherwise) and compiled for different processors, relying on compiler optimzation makes even more sense.

If you spent days on perfect hand optimization for a Pentium III processor, only to find the client is using AMD all that effort might be right down the drain.

Now if I were writing something for an embedded device I had control over all the hardware on, I might think differently. But I doubt it.

Wudang
30th January 2006, 03:51 AM
It depends: for example suppose you're doing an SQL call.
select clue from users where iq>100;
for some purpose a simple
if sqlcode = 0 then continue
else throw toys out

If you're doing something more important though you might want to:
switch (sqlcode)
case 0
continue
case +100
nosurprise = true
case -911
retry = true


etc etc.

Other times I choose one over the other
if (99.99% of cases) then continue
else figure out which of n other cases it is
That keeps the flow of "normal" processing uncluttered by code that only has to be invoked on rare occasions for special cases.

If there are more than 2 reasonably probable results I'll use switch or its equivalent. As has been said, make it easy for anyone reading the code to follow it.

cyborg
30th January 2006, 04:44 AM
Well, as El Greco points out, processors only have conditional branch instructions, so a switch and an if-then will compile to roughly the same code.

Not quite right.

Yes processors only have branching statements for control flow BUT they do not have to branch to a FIXED location as an IF statement might imply. The common optimisation for a switch statement is the use of a jump table to provide the branching destinations for the argument of the switch rather than a fall-through.

An array of function pointers as suggested is pretty much the right method (but there are far more efficient ways of storing such tables) but the main point I would emphasise is that you should definately structure your programs in such a way as that the logic is very clear and not try to do optimisations yourself. You will often just interfere with a compiler's attempts and compilers generally do a lot better than you ever will.

Use a switch statement for a task that is a switch. It's that simple really.

Oh and languages that require a break to get out a switch case, i hate those.

Then how exactly do these languages allow a fall-through?

a_unique_person
30th January 2006, 05:14 AM
They don't.

Upchurch
30th January 2006, 09:37 AM
...but the main point I would emphasise is that you should definately structure your programs in such a way as that the logic is very clear and not try to do optimisations yourself. You will often just interfere with a compiler's attempts and compilers generally do a lot better than you ever will.This is the main sentiment I'm getting. It's not as satisfying as "Oh, switch/if statements are definitely and noticibly faster, you'd be a fool to use anything else", but I can accept that.

Wudang
30th January 2006, 09:57 AM
This is the main sentiment I'm getting. It's not as satisfying as "Oh, switch/if statements are definitely and noticibly faster, you'd be a fool to use anything else", but I can accept that.

When you come back to the code a year later, or have to fix somebody else's code who also held this sentiment, you will find it deeply satisfying. Especially when you have experienced the reverse. :boggled:

Jekyll
30th January 2006, 10:12 AM
Then how exactly do these languages allow a fall-through?
With GOTOs of course.

Arkan_Wolfshade
30th January 2006, 12:09 PM
Rule of thumb I use in programming is, if it is an either/or then use if-else. Otherwise, use switch. Helps prevent nesting of ifs and, for Oracle at least, does perform slightly better.

kevin
30th January 2006, 03:45 PM
Oh and languages that require a break to get out a switch case, i hate those.

Then how exactly do these languages allow a fall-through?

a) if/else have no fall through, why should switch
b) how useful is fall through? I've found it useful very rarely and can be coded for easily.
c) it makes debugging hard when left out.

Why make the rare case the default?

PixyMisa
30th January 2006, 05:06 PM
If you spent days on perfect hand optimization for a Pentium III processor, only to find the client is using AMD all that effort might be right down the drain.
Actually, that specific case is the only one that does work well. :) Optimising Athlon/Opteron and for Pentium Pro/II/III/M is much the same. The Pentium 4 is very different. Trying to get my code running fast on both Intel and PowerPC was fun, though.

PixyMisa
30th January 2006, 05:07 PM
Then how exactly do these languages allow a fall-through?
They specify the fall-through rather than the break.

PixyMisa
30th January 2006, 05:10 PM
Premature optimization is the root of all evil. (http://www.petefreitag.com/item/509.cfm)

a_unique_person
30th January 2006, 05:40 PM
I have worked on optimising code before. A/Ps would take a long running program, look at what appeared to be something that was 'slow' and optimise it, only to find no real difference to the performance.

The only way to go about the process sensibly is to run a performance analyser over the code. Most of the code it really doesn't matter at all if it is optimised or not, it's just that 'hot spots' that are of interest. Depending on the application, it is often data access that this the cause of the problem, although badly written loops and SQL can be the problem too.

An if/then vs a switch is, for the type of applications I have worked on, (commercial financial/insurance, etc), neither here nor there.

Angus McPresley
31st January 2006, 05:22 AM
There is no case for fall-through on switch statement.

I'm not saying there's no cases where it will work for a given situation, but if you use it, it is never clear what's going on, and clarity should be your primary goal. If not, you might as well write it in assembly language.

I could maybe see a case where the fall-through cases have no associated code, e.g.

switch (letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': println( "Vowel" );
break;
default: println( "Consonant" );
}

but even then there's the "break" you might forget. To put it another way, if I inherit your code and see a "switch", consider it gone. ;-)

Jekyll
31st January 2006, 06:22 AM
I don't see why you think:
{
case 1:
indented code
more indented code
break:

case 2:
code code code
case 3:
code
}
is hard to read.

Edit:
Of course, if the forum code destroys my spacing, it's hard to read.

Angus McPresley
31st January 2006, 07:12 AM
I don't see why you think:
{
case 1:
indented code
more indented code
break:

case 2:
code code code
case 3:
code
}
is hard to read.

Edit:
Of course, if the forum code destroys my spacing, it's hard to read.


Even indented -- I didn't mean it was hard to read, I meant it was hard to spot the fall through. The average coder who comes in to modify the "case 3:" clause, even with the extra spacing, I doubt would notice that case 2 falls into it, and might leave behind unexpected behavior.

"If..else"s are just as clear in this situation, and much safer. IMO.

Darat
31st January 2006, 07:15 AM
By the way the forum has a useful tag for coders -

[code]
switch (day)
{
case 1 : cout << "Sunday";
break;
case 2 : cout << "Monday";
break;
case 3 : cout << "Tuesday";
break;
case 4 : cout << "Wednesday";
break;
case 5 : cout << "Thursday";
break;
case 6 : cout << "Friday";
break;
case 7 : cout << "Saturday";
break;
default : cout << "Not an allowable day number";
break;
}

MWare
31st January 2006, 07:29 AM
There are some OO purists here at my office who have stated to me that in the case of nearly any switch statement, subclassing can be used instead. This is a more structural than syntactic answer. Personally I am not as much of a purist and use switches whenever given a condition that I can test with a enumerated value. I don't enumerate anything unless there are three or more enumerable states. That probably didn't help at all, I shouldn't post before my first cup of coffee anymore.

epepke
1st February 2006, 11:33 PM
What is better: Switch statements or If...Else If statements? And why?

Traditionally in Pascal compilers, case statements (the equivalent of switch) used a hash table lookup, so they were faster for large numbers of cases.

I don't know if any C compilers do this.

a_unique_person
2nd February 2006, 02:24 AM
In practice, I don't know why there is the artificial accomodation between the high level language and how the switch is implemented. Surely that should be a compiler issue, and the switch should work like a COBOL select statement.



EVALUATE TRUE
WHEN WS-X = 1 AND WS-Y = 2
PERFORM X-100-PROCESS1
WHEN WS-X =1 AND WS-Y NOT = 2
PERFORM X-200-PROCESS2
END-EVALUATE.
Here, the whole condition on the WHEN statement is checked and if it is TRUE then the associated statement(s) are executed.

The second way to do this is using EVALUATE ... ALSO.

EVALUATE WS-AGE ALSO WS-SEX ALSO WS-WEIGHT
WHEN 21 ALSO 'M' ALSO 150
PERFORM A-200-ACCEPT
WHEN OTHER
PERFORM A-300-DECLINE
END-EVALUATE.




There is no need for break, fall through, or anything else. All optimisation is done as it should be, behind the scenes by the compiler.

jeremyp
5th February 2006, 06:30 PM
I don't see why you think:
{
case 1:
indented code
more indented code
break:

case 2:
code code code
case 3:
code
}
is hard to read.

Edit:
Of course, if the forum code destroys my spacing, it's hard to read.

I don't know about hard to read, but it is hard to maintain. If I were a maintainer looking at your code trying to find a bug and I came across the above, I have to waste some time figuring out if you meant case 2 to fall through or if you just forgot to put the break in. Of course, you can solve that particular issue by putting a comment in, but then what if we need to implement an enhancement that requires additional code to the top of case 3 but which shouldn't be implemented for case 2? We will do one of three things: 1) refactor the whole switch statement, 2) bodge it with an if statement, 3) forget about the fall through and introduce a bug in case 2.

Paul C. Anagnostopoulos
6th February 2006, 06:48 AM
switch (...) {
case 1:
indented code
more indented code
break:

case 2:
code code code
// Fall through to next case.

case 3:
code
}


Seems pretty clear to me. That said, I'd leave the fall-through option out of a language design.

~~ Paul

roger
6th February 2006, 07:42 AM
I like fall through only when you are combining several cases:


switch (machine_condition) {
case M_OK:
TurnGreenLightOn();
break;

case M_OFF:
TurnRedLightOn ();
break;

case M_ERROR:
case M_BADHEALTH:
case M_NORESPONSE:
TurnYellowLightOn ();
break;
}

So I suppose if I wrote a language I'd keep switch, get rid of break, but allow multiple cases for a unit of code:


switch (machine_condition) {
case M_OK:
TurnGreenLightOn();

case M_OFF:
TurnRedLightOn ();

case M_ERROR:
case M_BADHEALTH:
case M_NORESPONSE:
TurnYellowLightOn ();
}


I think that is somewhat more readable than the equivelant if/then series, since you don't have to parse for OR vs AND, etc.

Paul C. Anagnostopoulos
6th February 2006, 08:09 AM
Instead of multiple cases, just extend the syntax of the case clause:

case-clause: CASE {range-list | OTHER} :

range-list: {expression [.. expression]} $\bowtie$ ,

kevin
6th February 2006, 08:44 PM
Instead of multiple cases, just extend the syntax of the case clause:

case-clause: CASE {range-list | OTHER} :

range-list: {expression [.. expression]} $\bowtie$ ,

This is what I like, as long as range lists can be strings, continuous ranges, or discontinuous number ranges.

i.e.

case (1-7,30-40)
case ("Monday","Tuesday")

hmmm, probably need some way of marking the continuous ranges so they don't look like subtractions.

roger
6th February 2006, 09:04 PM
hmmm, probably need some way of marking the continuous ranges so they don't look like subtractions.Ada uses 1..7

El Greco
7th February 2006, 01:15 AM
In any case, why don't you make two tiny programs and compare the disassembled executables ?

If we're talking about C, my guess is they would be identical.

MRC_Hans
7th February 2006, 02:34 AM
Speaking C (and C++), I think it is clear:

If the options are a set of similar data (e.g. characters), the switch is the right thing to use, even if there is only a few options.

If there are many options, the switch is always right, because a long row of if-then-else become unreadable.

If you need to speed-optimize a switch, look up the options in a table.

The break; in switches has a very definite use: You may not want to leave the switch after the first match, you may want to execute the rest of the statements in the switch. This, of course, is a multi-entry, and thus dirty coding, still.....

Hans

Paul C. Anagnostopoulos
7th February 2006, 07:01 AM
This is what I like, as long as range lists can be strings, continuous ranges, or discontinuous number ranges.
Yes, the syntax allows a range to be indicated with the punctuation "..", like Ada. It also allows multiple ranges separated by commas (the bowtie indicates that the preceding syntax can be repeated using the succeeding punctuation).

My personal language, Gossip, also allows a range expression to be a pattern, in which case it is matched against the switch expression value.

~~ Paul

kevin
7th February 2006, 07:39 AM
Speaking C (and C++), I think it is clear:
The break; in switches has a very definite use: You may not want to leave the switch after the first match, you may want to execute the rest of the statements in the switch. This, of course, is a multi-entry, and thus dirty coding, still.....


I'm not arguing that executing the remaining statements won't occasionally be useful, just that this case is the rare case and therefore shouldn't be the default.

I'd rather see a continue; that indicates you do want to execute the next section, rather than a break; which means you don't.

Although continue is used in a lot of languages for loop control, so it probably needs to be a different word. But it's early and I can't think of one.

epepke
8th February 2006, 02:10 AM
In any case, why don't you make two tiny programs and compare the disassembled executables ?

If we're talking about C, my guess is they would be identical.

Not so.


*** EXECUTABLE CODE (.text) ***

Label Opcode Operands Comment

0x00000000 _Z6Switchl:
0x00000000 0x2800 cmp r0,#0
0x00000002 0xD004 beq *+12 ; 0x0000000e
0x00000004 0x2801 cmp r0,#1
0x00000006 0xD004 beq *+12 ; 0x00000012
0x00000008 0x2802 cmp r0,#2
0x0000000A 0xD004 beq *+12 ; 0x00000016
0x0000000C 0xE005 b *+14 ; 0x0000001a
0x0000000E 0x2001 mov r0,#1
0x00000010 0x4770 bx lr
0x00000012 0x2002 mov r0,#2
0x00000014 0x4770 bx lr
0x00000016 0x2004 mov r0,#4
0x00000018 0x4770 bx lr
0x0000001A 0x2000 mov r0,#0
0x0000001C 0x4770 bx lr


*** EXECUTABLE CODE (.text) ***

Label Opcode Operands Comment

0x00000000 _Z2Ifl:
0x00000000 0x2800 cmp r0,#0
0x00000002 0xD101 bne *+6 ; 0x00000008
0x00000004 0x2001 mov r0,#1
0x00000006 0x4770 bx lr
0x00000008 0x2801 cmp r0,#1
0x0000000A 0xD101 bne *+6 ; 0x00000010
0x0000000C 0x2002 mov r0,#2
0x0000000E 0x4770 bx lr
0x00000010 0x2802 cmp r0,#2
0x00000012 0xD101 bne *+6 ; 0x00000018
0x00000014 0x2004 mov r0,#4
0x00000016 0x4770 bx lr
0x00000018 0x2000 mov r0,#0
0x0000001A 0x4770 bx lr

jeremyp
9th February 2006, 06:38 PM
I'd rather see a continue; that indicates you do want to execute the next section, rather than a break; which means you don't.

Although continue is used in a lot of languages for loop control, so it probably needs to be a different word. But it's early and I can't think of one.
The semantics of the continue keyword in C are about as evil as it's possible to be. If you want to change it so that it only means "drop through this switch case" it gets my vote.

Paul C. Anagnostopoulos
9th February 2006, 06:47 PM
What's the problem with continue, Jeremy?

~~ Paul