Use cases for goto

If you've ever taken a C/C++ programming course as a student, you've almost certainly been told to avoid goto like the plague. Then you read some actual real-world code, like the Linux kernel (or any operating system code, really) and you see occasional gotos everywhere. At that point you start to wonder if there's something wrong with the people writing the Linux kernel or your professors - and, if you haven't already noticed, that's certainly what I was thinking.

This post is not meant to convince you to use goto everywhere, because that really is bad, but I want to present you with a few use cases where using goto won't only not hurt, but will also improve the performance and readability of your code.

Some use cases

The most important use case there is for a goto is by far error handling when there are more than 1 points of failure. In this case, you might want to cleanup some resources while also skipping part of the code that should not be executed, without having to deal with flags, helper functions, and other methods that would make the code ugly, slower and error prone. Try rewriting the following snippet without a goto:

	int
	foo(int *bar, int *baz)
	{
		if (!func1())
			goto fail;
		if (!func2())
			goto fail;
		if (!func3())
			goto fail;

		return 0;
	
	fail:
		warn("foo failed");
		if (bar != NULL)
			free(bar);
		if (baz != NULL)
			free(baz);

		return -1
	}
	

Here's also a random file in the Linux kernel that does pretty much the same thing:

Another use case is breaking out of deeply nested code. Let's say you have 3 for loops and there's a special case in which you really want to break out of all the loops at once. how do you do that? There are multiple ways you can go about doing so but one way would be to set a flag and check against it on every nested level.

	flag = 0;

	for (i = 0; i < 10; i++) {
		for (j = 0; j < 10; j++) {
			for (k = 0; k < 10; k++) {
				.
				.
				.
				if (flag)
					break;
			}
			if (flag)
				break;
		}
		if (flag)
			break;
	}
	

Now I don't know about you, but this code looks absolutely ugly and if it was actual code with more statements, you couldn't even understand what's going on. However, if you think that this way of solving the problem is good, then please seek help.

Another ugly hack you can use is something another colleague from university showed me, and something I would never use; when the flag is set, you can manually max out all the loop counters.

A pretty straight-forward solution would also be to put the loop into a function and use a return statement to break out of all the loops. That's actually a good solution, and I'm aware of it, but I want to provide with another solution, which is also quite faster than using a function since it avoids that additional function call.

An alternative, and in my opinion, better way of solving this problem would be by using a (don't say it, don't say it) goto.

	flag = 0;

	for (i = 0; i < 10; i++) {
		for (j = 0; j < 10; j++) {
			for (k = 0; k < 10; k++) {
				.
				.
				.
				if (flag)
					goto end;
			}
		}
	}
	end:
	.
	.
	.
	

Who cares, anyway?

Even in the case that these are just nitpicks, you might be thinking: is it really that important to know about them? The answer is yes.

In the first use case there isn't really a performance boost, but the code is much more readable and you avoid code duplication. In the second use case the goto solution actually does improve performance. The reason why is simple; we check for flag on every single loop, which means, that in case flag is never set, we'll have done 10 * 10 * 10 = 1000 checks just to see if flag is set. And that's just with 3 for loops going from 0 to 10 each; think how easily this can scale up if you add just a few more lines of code or increase the iterations.

On the other hand, the goto solution just does only one check in the third loop, which means that in the above scenario, where flag never gets set, we'll have done only 10 checks - that's 100 times faster than the other solution.

Using a function is almost just as fast as using a goto without a function, but not having to call a function is generally faster. But as I said, both solutions are great and totally valid, I just want to show an alternative one.

Final note

I hope I've made it clear that goto does have its place but it should be used carefuly, because if you overuse it, your code will either become incomprehensible, stupid or just flat out broken. It's also understandable why many professors teach students to not use goto; many people will misuse it, but I don't think it's right to teach students to never use it, as I've been taught to. The use cases I showcased in this post are very common and sometimes the code can be vastly improved with just a simple goto if used correctly.

Again, thanks to both my colleagues who helped me improve this article with their recommendations.