Friday 19 January 2024

Branching With Switch Statements

Decision blocks constitute a large part of programming. Much of the time, when someone mentions a decision in programming, the first thing to come to mind is an If block. And indeed, If blocks are amazingly versatile, able to handle just about all decision-making requirements in programming.

However, there are other options. And I would like to talk about Switch statements, which, while not quite as versatile as If statements, are better in certain use cases.

The Anatomy of a Switch statement

We begin a Switch statement with the keyword. In the case of C++ (and JavaScript, and Java) it's "switch". It then includes the variable, x, in parentheses, and the curly braces.
switch (x)
{

}


Assuming that the value of x is an integer, we populate the Switch statement with cases using the case keyword.
switch (x)
{
    case 1:
    case 10:
    case 35:
}


Optionally, there's a default case in the case that the value of x is not 1, 10 or 35.
switch (x)
{
    case 1:
    case 10:
    case 35:
    default:
}


If x is 1, we run the function a(). If x is 10, we run the function b(). If x is 35, we run the function c(). If it's none of the above, we run the function a(). Now that I say it like that, it sounds like this could be a multiple If statement block. However...
switch (x)
{
    case 1:
        a();
    case 10:
        b();
    case 35:
        c();
    default:
        a();
}


... we need break statements if we just want this to operate like a multiple If statement block. We'll get back to this soon.
switch (x)
{
    case 1:
        a();
        break;
    case 10:
        b();
        break;
    case 35:
        c();
        break;
    default:
        a();
        break;
}


In the meantime, this is what the same code would look like in PHP. Other than the mandatory dollar sign in front of the variable name, very little has changed.
switch ($x)
{
    case 1:
        a();
        break;
    case 10:
        b();
        break;
    case 35:
        c();
        break;
    default:
        a();
        break;
}


In Python, switch has been replaced by match, with no parentheses needed. This being Python, no semicolons are needed either. And Python automatically assumes you want a break statement, which may or may not be such a great idea.
match x:
    case 1:
        a()

    case 10:
        b()

    case 35:
        c()

    case -:
        a()


The anatomy of the Switch statement, barring keyword and syntax differences across these languages, are astonishingly similar. Some languages, like Python, omit the break statement altogether, in favor of a break by default.

The Flow-through

The break statement tells the compiler (or interpreter) that after executing the code associated with that particular case, execution should resume outside of the Switch statement. For the vast majority of programmers, that is what is intended. However, when the break statement is excluded, execution goes onto the next case (whether or not the case is a match), and so on until a break statement is encountered.

This is what is known as a "Flow-through".

How useful is this? Well, in the case below, if you want the code a() and b() to execute when x is 1, and only b() to execute when x is 2, then yes this would work.
switch (x)
{
    case 1:
        a();
    case 2:
        b();
        break;
    case 3:
        c();
        break;
    default:
        a();
        break;
}


However, this case is so obscure and (in my opinion) unintuitive that doing this deliberately will not register immediately to someone reading the code. A programmer is far better off simply relying on the classic If-else.

Advantages over If blocks

In terms of switching execution for simple comparisons, especially in multiple simple comparisons, a Switch statement is far more readable. The following is a series of If blocks. Each of these is a simple comparison, with each If block containing multiple statements. The comparison is read three times.
if (x == 0)
{
    // multiple program statements
    // ...
    // ...
}

if (x == 1)
{
    // multiple program statements
    // ...
    // ...
}

if (x == 5)
{
    // multiple program statements
    // ...
    // ...
}


This can be condensed into a single Switch statement for the variable x. The cognitive load on the one reading this code is less. We understand the intent immediately; these are all the permutations of the variable x.

Also, the comparison is read one time in this scenario. The performance gain here is minimal; but what if there were ten, or fifty different values to cater for?
switch (x)
{
    case 0:
        // multiple program statements
        // ...
        // ...
        break;
    case 1:
        // multiple program statements
        // ...
        // ...
        break;
    case 5:
        // multiple program statements
        // ...
        // ...
        break;
    default:
        // multiple program statements
        // ...
        // ...
        break;
}


Disadvantages compared to If blocks

The Switch statement is meant for simple comparisons against enumerated or string values. For more complex cases, the If or If-else statement is still the way to go.

Something like this, for instance, is not possible in a Switch statement. This has two comparisons involving three variables - x against y and y against z.
if (x == y || (y < (z * 10.5)))
{
    // multiple program statements
    // ...
    // ...
}


We could use more complex comparisons using the Switch statement, but then one of the main advantages - readability - would be compromised.
switch (x)
{
    case (y * 10.5):
        // multiple program statements
        // ...
        // ...
        break;
    case (z / 10):
        // multiple program statements
        // ...
        // ...
        break;
    case "hello world":
        // multiple program statements
        // ...
        // ...
        break;
    default:
        // multiple program statements
        // ...
        // ...
        break;
}


In a nutshell

There are use cases for the Switch statement, and it's incredibly useful for simple comparisons against one variable. For everything else, use the If or If-else block as a fallback.

Your Iffy programmer,
T___T

No comments:

Post a Comment