---
title: "goto in action - The exception from the rule"
description: "A lot of developers will say never use `goto`. This keyword is bad as it promotes [spaghetti code](https://en.wikipedia.org/wiki/Spaghetti_code). But as so often in live the exception confirms the rules. Let's see where `goto` can increase the readability and maintainability."
updated: 2022-06-18
tags: ["C#", "goto"]
canonical: "https://steven-giesel.com/blogPost/a1de0393-e0f9-491e-8c26-8ec34da60d16/goto-in-action-the-exception-from-the-rule"
---

# goto in action - The exception from the rule

`goto` is one of those keywords where almost everyone agrees that it is considered "bad". But there are valid uses cases for that.
The first question we have to ask ourselves is **Why is it bad?**.

## Why is `goto` bad?
There two main reasons I want to show:
 1. In almost any case where you use a `goto` it tends to be easier when you refactor code. 
 2. `goto` lets your control flow jump around

Let's assume you have the following code:
```csharp
for (var i = 0; i < n; i++)
{
    for (var j = 0; j < m; j++)
    {
        if (condition)
            goto EndOfLoop;
    }
}
EndOfLoop:
Console.Write("Do something here");
```

Here `goto` seems a viable choice, doesn't it? Consider the alternative with `break`. `break` allows only to break out one level:
```csharp
var breakOut = false;
for (var i = 0; i < n; i++)
{
    for (var j = 0; j < m; j++)
    {
        if (condition)
        {
            breakOut = true;
            break;
        }
    }
    if (breakOut)
        break;
}
```

Not that beautiful. So one could say that is a valid use case. But as said earlier those situtations tend to have better solutions where we refactor the whole loop into its own function an return directly a value bypassing any use of `goto` or `break` in the first place.

## The valid use case
Of course it boils down to personal preference and also the stuff shown below can be considered less maintainable or readable. Anyway I want to present: `goto case`. Oversimplified have a look at this:
```csharp
enum PathKind
{
    Relative = 0,
    Absolute,
}

private void SaveFile(string relativeOrAbsolutePath, PathKind pathKind)
{
    switch(pathKind)
    {
        case PathKind.Relative:
            relativeOrAbsolutePath = Path.Combine(currentPath, relativeOrAbsolutePath);
            SaveFile(relativeOrAbsolutePath);
            break;
        
        case PathKind.Absolute:
            SaveFile(relativeOrAbsolutePath);
            break;
}
```

We see that in both cases we want to save a file with the absolute path but we can't share that logic.
Now why not using **C** style with *fall through control flow* like this:
```csharp
private void SaveFile(string relativeOrAbsolutePath, PathKind pathKind)
{
    switch(pathKind)
    {
        case PathKind.Relative:
            relativeOrAbsolutePath = Path.Combine(currentPath, relativeOrAbsolutePath);
            SaveFile(relativeOrAbsolutePath);
        
        case PathKind.Absolute:
            SaveFile(relativeOrAbsolutePath);
            break;
}
```

Easy answer: [Because C# does not allow this](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0163).

Meet **`goto case`**:

```csharp
private void SaveFile(string relativeOrAbsolutePath, PathKind pathKind)
{
    switch(pathKind)
    {
        case PathKind.Relative:
            relativeOrAbsolutePath = Path.Combine(currentPath, relativeOrAbsolutePath);
            goto case PathKind.Absolute;
        
        case PathKind.Absolute:
            SaveFile(relativeOrAbsolutePath);
            break;
}
```


## Resources:
 * `goto` in the [Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements)