Introduction
There has been a lot of hysteria about the 'goto' statement since the famous
computer scientist, Edsger Dijkstra, said in 1968 that he considered it to be
"harmful".
In those days, he had a point because the 'goto' statement produced a lot of
spaghetti code particularly by those using early versions of the BASIC
programming language.
Despite this warning, 'goto' was included in C, C++ and C#. It wasn't included
in Java though they do have labelled 'break' and 'continue' statements which
achieve much the same thing.
In C#, it's much tamer than in some other languages as you can't jump into a
nested block; you can only jump out of (or within) one. As far as the compiler
is concerned, it works quickly because it can be mapped directly to CIL, and
thence to native code, 'jump' instructions.
Although 'goto' isn't needed much in modern programming and it's always possible
to program around it, I believe its use is acceptable in certain scenarios which
I'd like to examine in this article. The scenarios presented are not necessarily
exhaustive.
Jumping between 'case' blocks in a 'switch' statement
Unlike C, C++ and Java, C# doesn't permit code to 'fall through' from one case
block to another unless the first case block is empty. This eliminates some
potentially hard to find bugs. If you do need to fall through, you can use the
'goto case' construct instead:
string
position = "first";
switch
(position)
{
case "first":
DoSomething();
goto case
"second"; // not allowed to 'fall through'
here
case "second":
DoSomethingElse();
break;
}
This is nice and clean and I don't think many
C# developers would quarrel with this usage.
Jumping out of (or within) deeply nested loops
The 'break' statement only jumps out of the current loop. If you want to exit
from two or more nested loops, then the usual solution is to use bool variables
in the following manner:
bool
finished = false;
for
(int i = 0; i < 10; i++)
{
while (someCondition)
{
// ....
if (someOtherCondition)
{
finished = true;
break;
}
}
if (finished) break;
}
Now, this is a reasonable solution when you
only have two nested loops but, if you have more than this, then it can become
unwieldy and error prone. In this situation, using 'goto' is much simpler and
clearer:
for
(int i = 0; i < 10; i++)
{
for (int j =
0; j < 10; j++)
{
while (someCondition)
{
// ....
if (someOtherCondition)
{
goto finished;
}
}
}
}
finished:
// code following loops
Similar considerations apply to the 'continue'
keyword which can only continue the current loop. If you want to continue an
outer loop, then 'goto' can be used instead of bool variables:
for
(int i = 0; i < 10; i++)
{
for (int j =
0; j < 10; j++)
{
while (someCondition)
{
// ....
if (someOtherCondition)
{
goto continuation;
}
}
}
continuation: ; // empty statement here
}
Although having to jump to an empty statement
is rather ugly, it's usually cleaner than the alternatives.
Retrying code after making corrections
The situation sometimes arises where you'd like to try a piece of code and, if
it fails, make a correction and try it again. As C# lacks a 'retry' statement,
you might come up with code such as this:
int
x = 4, y = 0;
int
z;
bool
success;
do
{
success = true;
try
{
z = x / y;
}
catch (DivideByZeroException)
{
y = 2;
success = false;
}
} while (!success);
Console.WriteLine(z);
This works and isn't too bad but using 'goto'
is cleaner and clearer:
int
x = 4, y = 0;
int
z;
retry:
try
{
z = x / y;
}
catch
(DivideByZeroException)
{
y = 2;
goto retry;
}
Console.WriteLine(z);
Conclusion
I should warn you now that prejudice against the 'goto' statement runs very deep
and its use is often banned by some programming teams. However, I hope I've
demonstrated that there are a few scenarios where its use may be beneficial so
don't ignore it, if you have the choice!