A Comprehensive Walkthrough of C# Jump Statements Part 2 - goto
You can use goto to customize your logic flow, even use it to simulate recursion, iteration, and selection.
Jun 14, 2019 • 9 Minute Read
Introduction
This is the second part of a two-part series on C# Jump Statements. In the first part, We delved into break and continue statements and how they works in nested loop. Check it out in case you missed it.
In this guide, we will focus on another important jump statement: goto statement. We will talk about the scope of usages and also pointed out the side effect of goto. Then we will mention other jump statements.
As the last guide of C# flow control, we will summarize the relation between iterative, conditional and jump statements.
As a tutorial for beginners, I try my best to use vivid visualizations and examples to help you understand.
- First, I will start with an interesting scenario.
- Then I will show you the code templates and flowcharts of all kinds of jump statements.
- In addition, we compare them and summarize the best practice.
- Finally, we will talk about advanced usages.
goto Statement
goto is a powerful jump statement. It can jump to anywhere in the same action scope. You can use goto to customize your logic flow, even use it to simulate recursion, iteration, and selection.
Syntax
There are two ways to use goto in C#:
- goto in switch: it is the only way a non-empty case falls through to another case in C# switch.
- goto with label: First, we label a statement by label_name: statement;, then we can goto this statement via label_name. Notice label should be defined in the same action scope.
goto in switch
Let's practice goto in switch with the following hard-working programmer example:
string state = "hungry";
switch (state)
{
case "normal":
Console.WriteLine("coding..");
goto default; // jump to default branch
case "hungry":
Console.WriteLine("eat some stuff");
goto case "normal"; // jump to "normal" branch
case "illness":
Console.WriteLine("see a doctor");
break;
default:
Console.WriteLine("go to sleep");
break;
}
If state is "hungry", first process "hungry" case logic, then jump to "normal" branch, finally fall through to default.
eat some stuff
coding..
go to sleep
goto with Label
For goto with label, the most appropriate usages are jumping in multiple nested loops or conditions.
We have learned break can only take effect on the current loop in nested loops. A straightforward idea is using a flag to mark the state, and process it in outer loops.
Here is a version of nested loops with flag:
int[,,] arr = new int[2, 3, 2] {
{ { 1, 2 }, { 3, 4 }, { 5, 6 } },
{ { 7, 8 }, { 9, 10 }, { 11, 12 } } };
bool flag = false;
for (int i = 0; i < arr.GetLength(0); ++i)
{
for (int j = 0; j < arr.GetLength(1); ++j)
{
for (int k = 0; k < arr.GetLength(2); ++k)
{
if (arr[i, j, k] == 7)
{
flag = true;
break;
}
Console.WriteLine("current element is {0}", arr[i, j, k]);
}
if (flag)
break;
}
if (flag)
break;
}
Console.WriteLine("break multiple loops when value is 7");
This is the version with goto:
for (int i = 0; i < arr.GetLength(0); ++i)
{
for (int j = 0; j < arr.GetLength(1); ++j)
{
for (int k = 0; k < arr.GetLength(2); ++k)
{
if (arr[i, j, k] == 7)
goto Finish;
Console.WriteLine("current element is {0}", arr[i, j, k]);
}
}
}
Finish: Console.WriteLine("break multiple loops when value is 7");
Pretty concise and elegant, right?
Other Usages
Except for the above two main usages, here are some other usages.
We can regard goto as the way to customize our control flow, such as simulating recursion, iteration, and selection.
We use do-while as an example to show how to use goto to simulate:
// do-while template
do
{
code_block;
} while (condition);
// rewritten by goto
Loop: code_block;
if (condition)
goto Loop;
Here is the for-else statement in python. If not break from the loop, it will execute the else part.
for x in range(5):
if x == 3:
print("find 3 in loop")
break
else:
print("not find 3 in loop") # reach there when not break
C# don't support for else, but we can achieve this by goto easily.
for (int i = 0; i < 5; ++i)
{
if (i == 3)
{
Console.WriteLine("find 3 in loop");
goto Finish;
}
}
Console.WriteLine("not find 3 in loop");
Finish: Console.WriteLine("end of loop");
But these usages are not recommended. We will discuss the side-effect of goto later.
Side Effect
Once goto is invented, arguments never stop. I refer to the famous opinions from wiki goto:
Probably the most famous criticism of GOTO is a 1968 letter by Edsger Dijkstra called Go To Statement Considered Harmful. In that letter, Dijkstra argued that unrestricted GOTO statements should be abolished from higher-level languages because they complicated the task of analyzing and verifying the correctness of programs (particularly those involving loops). An alternative viewpoint is presented in Donald Knuth's Structured Programming with go to Statements which analyzes many common programming tasks and finds that in some of them GOTO is the optimal language construct to use.
Here is a negative example of goto, with spaghetti code twisted together:
// negative example of goto, tangled code
int x = 0;
Label1: x += 1;
if (x % 2 == 0)
goto Label1;
if (x % 3 == 0)
goto Label2;
Console.WriteLine(x);
Label2: if (x < 10)
goto Label1;
The readability is awful. It is weakly structured and hard to debug or maintain.
My suggestion is:
In modern language, there are many alternatives for goto, such as context manager, design pattern, and other control flow methods. Except for usages in switch and nested loops, we should avoid using goto as much as possible.
Other Jump Statements
There are other jump statements, but they are applied to specific situations.
- return statement terminates the execution of the method in which it appears and returns control to the calling method.
- throw an exception when an anomaly occurs and abandon the rest logic.
We mainly focus on the general jump statements and are not going to expand them here. You can refer to the official documents if you are interested.
Relation between Control Flow Statements
We have learned all the basic control flow statements. At the end of this series, let's summarize the relation between iterative, conditional and jump statements.
I draw a relation diagram to help you understand:
They depend on each other and enhance each other.
They are inseparable. They are indispensable.
Together, they form complex program logic.
Conclusion
In this guide, we have learned another jump statement: goto statement. We analyzed the syntax and flowchart of goto and practiced with examples. We talked about the scope of usage and also pointed out the side effect of goto. Besides, we mentioned other jump statements. In the end, we summarized the relation between iterative, conditional and jump statements.
As this is the end, I have drawn a mind map to help you organize and review the knowledge in this series.
This guide is one of a series of C# Flow Control guides:
- A Comprehensive Walkthrough of C# Iterative Statements Part 1 - while, do
- A Comprehensive Walkthrough of C# Iterative Statements Part 2 - for, foreach
- A Comprehensive Walkthrough of C# Iterative Statements Part 3 - advanced usages
- A Comprehensive Walkthrough of C# Conditional Statements Part 1 - if, else
- A Comprehensive Walkthrough of C# Conditional Statements Part 2 - switch
- A Comprehensive Walkthrough of C# Jump Statements Part 1 - break, continue
- A Comprehensive Walkthrough of C# Jump Statements Part 2 - goto
Hope you enjoyed it. If you have any questions, you’re welcome to contact me at recnac@foxmail.com.