Author avatar

Recnac

A Comprehensive Walkthrough of C# Jump Statements Part 2 - goto

Recnac

  • Jun 14, 2019
  • 9 Min read
  • 375 Views
  • Jun 14, 2019
  • 9 Min read
  • 375 Views
Programming Languages
C#

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.

  1. First, I will start with an interesting scenario.
  2. Then I will show you the code templates and flowcharts of all kinds of jump statements.
  3. In addition, we compare them and summarize the best practice.
  4. 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.

jump statements goto flowchart

goto in switch

Let's practice goto in switch with the following hard-working programmer example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
csharp

If state is "hungry", first process "hungry" case logic, then jump to "normal" branch, finally fall through to default.

1
2
3
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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");
csharp

This is the version with goto:

1
2
3
4
5
6
7
8
9
10
11
12
13
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");
csharp

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:

1
2
3
4
5
6
7
8
9
10
// do-while template
do
{
    code_block;
} while (condition);

// rewritten by goto
Loop: code_block;
if (condition)
	goto Loop;
csharp

Here is the for-else statement in python. If not break from the loop, it will execute the else part.

1
2
3
4
5
6
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
python

C# don't support for else, but we can achieve this by goto easily.

1
2
3
4
5
6
7
8
9
10
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");
csharp

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:

1
2
3
4
5
6
7
8
9
10
// 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;
csharp

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:

relation between flow control statements

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.

jump statements mind map

This guide is one of a series of C# Flow Control guides:

Hope you enjoyed it. If you have any questions, you’re welcome to contact me at [email protected]

0