Monday, May 19. 2008
This article discusses some common usage scenarios of the goto keyword and shows alternative approaches.
If someone would have asked me a few years ago when to use the goto keyword I would have answered (in capital letters): NEVER!! GOTO’S ARE EVIL! (and obviously you get attacked by raptors if you use them)
Like many I have been educated to have a emotional reaction when someone mentions the goto keyword. Emotions have nothing to do with good practices, so lets take a pragmatic look on some of the common usages of goto and see what the real value of the goto keyword is.
Using goto to provide a single exit point.
The author of Sams Teach Yourself C# in 24 Hours (published by O’Reilly) describes the usage of gotos like this: (code slightly modified to make it more readable)
The author suggests using gotos for cleanup code and to provide a single exit point. This seems logical and it might be the most common use of gotos, it is however in C# absolutely unnecessary. (I guess if someone wants to learn C# in 24 hours there is no time to learn it the ‘right’ way.) To force cleanup code we can and should use a simple try - finally pattern (read more about it in my article).
We can rewrite the code above to this
private void btnGoto_Click(object sender, System.EventArgs e)
This approach has two major advantages:
Using goto to jump between switch statements.
Coming up with a reasonable example for a goto in a switch statement has proven to be difficult, which in itself might be an indicator for its usefulness. Anyway, basically you can jump from one case in a switch code block to another using the goto statement.
Let’s just take a look at this code snippet to discuss some of the upsides and downsides of goto statements in a switch code block. One good thing with labels in the switch statements (case 1, case 2 ect.) is that they are only accessible within the scope of the switch statement, which means that you cannot jump into the switch statement. This makes it easier to read but as you can see in the example above it makes it more complicated to follow the execution since it is no longer linear. Especially if the switch block is longer than a page and you use conditional goto’s (such as the one in the if (someExpression) block) it can be a real challenge to follow the execution flow. Unfortunately there is nothing to prevent you from defining a loop in which case the program will cause a StackOverFlowException. In the example above the goto case 1 in case 2 sends it back to case 2 and it could potentially be send back to case 1 again creating a loop. I would suggest to be open for the usage of the goto statement in switch blocks unlesst he complexity is high enough to make it painful to debug or there are possibilities for loops.
Using goto to break out of nested loops.
Another popular usage of gotos is breaking from nested loops. Unfortunately there is no break all keyword that would help us to break out of nested loops so we have to find another way of doing this.
for (int i = 0; i < 25; i++)
As long as the exitLoop label is immediately after the loop there is little chance that anything goes wrong here thus I think it is quite okay to use goto this way but you can also use a bool variable to achieve the same.
The later has the disadvantage that you have to remember to check for the breakAll variable in every loop. A better option in my opinion is to refactor the nested loops into a single method where you can use the return statement in order to break out of them.
So, when do you use goto’s?
I didn’t have to use a single goto statement in production code myself but I can see some situations where it might be efficient to use one. I guess the reason why I am not using it is because most of the time there is a better or equal alternative and I am one of these developers who enjoys refactoring/improving code which means that if I have to chose between ‘refactor the program flow’ or ‘use this one little goto statement’ it is highly likely that I will do the former. (and that has nothing to do with my fear of raptors)
Display comments as (Linear | Threaded)
the problem with using try -- finally as you describe instead of goto is that you may be hiding exceptions by not catching them. Or having to throw them to get to the finally and skip the rest of the code. Throwing an exception seems extreme when you just want to miss a few lines of code.
@Brian: if you just use try - finally you are not actually catching any exceptions - therefore you are not hiding any. if you need to catch exceptions you have to use a catch block. To skip the rest of the code you can simply use a return statement. this will skip the code in the try block and continues to execute in the finally block. for more information have a look at my other article which discusses the try - finally pattern: http://www.dotnettoad.com/index.php?/archives/14-finally-yes,-seriously-finally.html
good point about catching exceptions ... not sure what I ws thinking. But the reason I came across this post is I'm looking for a solution. I have a message processor and there are several points at which the message can be deemed 'invalid' and therefore no more processing is neccesary. At each point it would be easier to use a goto to get to the end (and tidy up). But I don't want to use goto, it just deson't feel right (not because of raptors).