views:

860

answers:

4

In my code I need to be able to jump (goto) a different case within the same switch statement. Is there a way to do this?

My code is something like this: (There is a lot of code I just left it all out)

switch (viewNumber) {
case 500:
        // [...]
break;

case 501:
        // [...]
break;
.
.
.
.
.

case 510:
        // [...]
break;

default:
break;

}

Thank you for your time! -Jeff

+8  A: 

It's generally very bad practice to unconditionally jump like you're asking.

I think a more readable/maintainable solution would be to place the shared code in a method and have multiple cases call the method.

If you really want to, you can use goto to do something like:

switch(viewNumber) {
    case 500:
        // [...]
        goto jumpLabel;
    case 501:
        // [...]
        break;
    case 502:
        // [...]
        jumpLabel:
        // Code that 500 also will execute
        break;
    default:break;
}

Note: I only provided the code example above to answer your question. I now feel so dirty I might have to buy some Bad Code Offsets.

Ben S
Thank you. The switch statement is in a method:- (IBAction) showViewAction:(id) sender{ viewNumber = [sender tag];But the case # I am using is the Tag ID from the sender. So when the user taps a button with tag ID 500 the method uses that tag to know what case to use.
Jeff
So this method must be enormous! Removing the code from the `case` statements and putting them in other methods might make things easier to read. Also, if you have a static number of buttons, you could directly associate each button to its own method using target-action.
Ben S
The way I used to have it was a separate method for each one of the cases and in IB all the buttons were connected to the "IBAction", but my boss feels that the code would be "more reliable, elegant, and run faster" if I used a Switch statement instead of separate methods. So your saying it would be better to use separate methods again? Also I heard before that "goto" is bad to use...Do you know why it is bad?
Jeff
There are tons of questions that discuss goto on SO (http://stackoverflow.com/search?q=goto+bad). I think the switch is much *less* elegant, especially if some of the buttons aren't related in any way. It's much more difficult to read since there's so much code in one place that isn't related and for every button press you need to run through a large set of comparisons to find the correct case block. IMO, it's much better to have the button simply call the code it needs to than having to pass through a switch "filter" like this.
Ben S
You also shouldn't even think about optimizing this sort of stuff unless your have performance issues, and profiling the application reveals this to be the cause. The number of nanoseconds saved (if this is even faster, which I doubt) will not offset the hours of maintenance that will go into it.
Ben S
Instead of breaking it out into separate methods that you wire individually, the best approach could well be leave the method you have (so only one point to wire to) but as others are suggesting, take all the common code and put that in a method you call from the switch statement.
Kendall Helmstetter Gelner
I agree with Kendall. It may be that the switch statement is fine, but break all the common parts out into functions. As to why goto is considered harmful, it all boils down to readability, and the potential for over/mis-use. gotos make code harder to understand because you have to jump all around, and when looking at a line of code, you don't know how you got there... [In general, "Never use goto statements. EVER" is one of those rules that you should NEVER break; unless you understand why it is a rule, and can therefore break it safely.]
Brian Postow
A: 

You should probably try rewrite your code, like a recursive call or just factor out common stuff and call a separate function. But as a fix and quick answer to your question you could put a label before your switch and goto it, like so

switchLabel:
switch(viewNumber) {
  case 500: {
    viewNumber = 501;
    goto switchLabel;
  }
}

Not sure of the Objective-C syntax here, but you could also try a variation thereof

int lastView = 0;

while (lastView != viewNumber)
  switch(lastView = viewNumber) {
    case 500: {
      viewNumber = 501;
      break;
    }
  }

which will keep on looping until the viewNumber doesn't change any more. This is still pretty much just a pretty-looking goto though.

And since we're doing gotos you could just goto into another case, as pointed out already. You could also do fancy stuff similar to Duff's device, by putting cases inside of other blocks. But that's just mad.. :)

roe
Thank you very much!
Jeff
+3  A: 

Instead of using goto, refactor your code so that the two (or more) cases that use common code instead call it in a common method.

Something like:

switch (value) {
   case (firstValue):
       // ...
       break;
   case (secondValue):
       [self doSharedCodeForSecondAndThirdValues];
       break;
   case (thirdValue):
       [self doSharedCodeForSecondAndThirdValues];
       break;
   default:
       break;
}

// ...

- (void) doSharedCodeForSecondAndThirdValues {
   // do stuff here that is common to second and third value cases
}

It wouldn't be the end of the world to use goto, though it is bad practice.

The practical reason for avoiding use of goto is that you have to search through your swtich-case tree to find that goto label.

If your switch logic changes, you'll have a messy situation on your hands.

If you pull out common code to its own method, the code is easier to read, debug and extend.

Alex Reynolds
A: 

[I'm making this answer community wiki because this doesn't actually answer the question per se]

As others have said, this is very bad style, and makes for unreadable code...

Alternatives:

  1. Factor the common code into a separate function, and call that in 2 places.
  2. Use fallthroughs, leave off the the break on a case and it falls through to the next one (remember, cases don't have to be in numerical order!)
  3. if you only want part of a case to be done in the other case, protect it with an if:

as in

case 500:
 .
 .
 .
case 501:
    if(viewNumber == 501)    {
     .
     .
     .
    }
     .
     .
     .
    break;
Brian Postow
Very nice to know thank you
Jeff