C# Goto

Goto keyword

Statements execute one after another. With the goto statement, though, we transfer control to a named label elsewhere in the method. Goto can be used to exit a deeply nested loop. As are many things, it is considered harmful.

Example

Piece of computer software: a program

To start, we examine a program that uses goto to exit a loop in the C# language. You can use code that does the same thing without goto, but would need a flag variable (usually a bool) to check.

Bool

Label:With a label, we indicate where a goto-statement should transfer control.

Based on:

.NET 4.5

Program that uses goto: C#

using System;

class Program
{
    static void Main()
    {
	Console.WriteLine(M());
    }

    static int M()
    {
	int dummy = 0;
	for (int a = 0; a < 10; a++)
	{
	    for (int y = 0; y < 10; y++) // Run until condition.
	    {
		for (int x = 0; x < 10; x++) // Run until condition.
		{
		    if (x == 5 &&
			y == 5)
		    {
			goto Outer;
		    }
		}
		dummy++;
	    }
	Outer:
	    continue;
	}
	return dummy;
    }
}

Output

50
Squares

In this example, method M contains three nested loops. The first loop iterates through numbers [0, 9], as do the two inner loops. But in the third loop, a condition is checked that causes the loop to exit using the break keyword.

ForBreak

The code increments the dummy variable after each completion of the inner loop. If the inner loop is exited early, this variable should be left alone. With the goto statement, it is not incremented.

Result:The value 50 is printed to the console.
The int is incremented 10 x 5 times.

However:If the goto was a break, the result would be 10 x 10 times, or a total of 100.

Example 2

Performance optimization

Continuing on, we show how to rewrite code that uses the break and continue keywords to use the goto and continue keywords. You may think the goto code is clearer. It uses one fewer variable.

Note:This benchmark is of limited utility. It does show how the JIT may be affected by the goto statement.

Code that uses break for loop: C#

static int BreakMethod()
{
    int dummy = 0;
    for (int a = 0; a < 10; a++)
    {
	for (int y = 0; y < 10; y++) // Run until condition.
	{
	    bool ok = true;
	    for (int x = 0; x < 10; x++) // Run until condition.
	    {
		if (x == 5 &&
		    y == 5)
		{
		    ok = false;
		    break;
		}
	    }
	    if (!ok)
	    {
		break;
	    }
	    dummy++;
	}
	continue;
    }
    return dummy;
}

Code that uses goto on loop: C#

static int GotoMethod()
{
    int dummy = 0;
    for (int a = 0; a < 10; a++)
    {
	for (int y = 0; y < 10; y++) // Run until condition.
	{
	    for (int x = 0; x < 10; x++) // Run until condition.
	    {
		if (x == 5 &&
		    y == 5)
		{
		    goto Outer;
		}
	    }
	    dummy++;
	}
    Outer:
	continue;
    }
    return dummy;
}
Note

Break example. This code uses a flag variable named "ok". It initializes the variable to true, but then sets it to false and breaks when the exit condition is reached. This avoids incrementing the dummy variable. The result is 50.

True, False

Next:The goto example has the same effect. It detects the exit condition and uses goto to leave the inner loop. It has no flag variable.

Benchmark

Just-in-time compiler: JIT

The two methods above were placed in a benchmark framework. They were run in a loop for many iterations, and the function result was checked each time. They were run with the break first and the goto second, and the other way around.

So:The results were that goto performed worse when it was run first. Timings are shown next.

Benchmark
Performance results

break:   1033 ms   (goto tested first)
goto:    1156 ms

break:   1036 ms   (break tested first)
goto:    1029 ms

The behavior observed here shows that goto is sometimes not optimized as well with the JIT compiler. Goto is only slower when called in the first loop. This might mean that the JIT compiler does not work as well with it.

Therefore:With these methods, break is faster because it is more reliably JIT-optimized.

JIT

Switch

Programming tip

The goto statement also can be used in a switch block. The switch allows control to be transferred to another case in this way. Goto still transfers the flow of control, but causes somewhat less confusion in switch.

Goto Switch

Summary

Goto may look faster and convenient. But it can actually confuse the runtime and result in poorer performance. In other words, goto is not only more complex for programmers, but is more difficult for the JIT compiler to optimize.

Spaghetti Code

C#: Loop