• Quick note - the problem with Youtube videos not embedding on the forum appears to have been fixed, thanks to ZiprHead. If you do still see problems let me know.

Switch vs If

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.
 
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. ;-)
 
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 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.
 
By the way the forum has a useful tag for coders -
Code:
[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;
  }
 
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.
 
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.
 
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.

Code:
[FONT=Courier New,Lucida Console,Courier,Monaco,Monospace,monospace][SIZE=-1]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.[/SIZE][/FONT]                              [FONT=Verdana,Tahoma,Arial,Helvetica,Sans-serif,sans-serif][SIZE=-1]
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.

[/SIZE][/FONT][FONT=Courier New,Lucida Console,Courier,Monaco,Monospace,monospace][SIZE=-1]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.
[/SIZE][/FONT]
 [FONT=Courier New,Lucida Console,Courier,Monaco,Monospace,monospace][SIZE=-1]
[/SIZE][/FONT]
[FONT=Courier New,Lucida Console,Courier,Monaco,Monospace,monospace][SIZE=-1]
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.
[/SIZE][/FONT]
 
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.
 
Code:
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
 
I like fall through only when you are combining several cases:

Code:
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:

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.
 
Instead of multiple cases, just extend the syntax of the case clause:

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

range-list: {expression [.. expression]} [latex]$\bowtie$[/latex] ,
 
Instead of multiple cases, just extend the syntax of the case clause:

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

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

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.
 
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.
 
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
 
Kevin said:
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
 
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.
 
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.

Code:
			*** 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
 

Back
Top Bottom