Luca's meaningless thoughts  

Unintentional fall-through in D's switch statements

by Leandro Lucarella on 2009- 11- 21 02:34 (updated on 2009- 11- 21 02:34)
tagged d, en, fall-through, patch, switch - with 2 comment(s)

Removing switch fall-through from D's switch statement is something discussed since the early beginnings of D, there are discussions about it since 2001 and to the date [*]. If you don't know what I'm talking about, see this example:

switch (x) {
case A:
    i = x;
    // fall-through
case B:
    j = 2;
    break;
case C:
    i = x + 1;
    break;
}

If you read carefully the case B case A code, it doesn't include a break statement, so if x == A not only i = x will be executed, the code in case B will be executed too. This is perfectly valid code, introduced by C, but it tends to be very error prone and if you forget a break statement, the introduced bug can be very hard to track.

Fall-through if fairly rare, and it would make perfect sense to make it explicit. Several suggestions were made in this time to make fall-through explicit, but nothing materialized yet. Here are the most frequently suggested solutions:

  • Add a new syntax for non-fall-through switch statements, for example:

    switch (x) {
    case A {
        i = x;
    }
    case B {
        j = 2;
    }
    case C {
        i = x + 1;
    }
    
  • Don't fall-through by default, use an explicit statement to ask for fall-through, for example:

    switch (x) {
    case A:
        i = x;
        goto case;
    case B:
        j = 2;
        break;
    case C:
        i = x + 1;
        break;
    }
    

    Others suggested continue switch or fallthrough, but I think some of this suggestions were made before goto case was implemented.

A few minutes ago, Chad Joan has filled a bug with this issue, but with a patch attached 8-). He opted for an intermediate solution, more in the lines of new switch syntax. He defines 2 case statements: case X: and case X!: (note the !). The former doesn't allow implicit fall-through and the latter does. This is the example in the bug report:

switch (i)
{
    case 1!: // Intent to use fall through behavior.
        x = 3;
    case 2!: // It's OK to decide to not actually fall through.
        x = 4;
        break;

    case 3,4,5:
        x = 5;
        break;

    case 6: // Error: You either forgot a break; or need to use !: instead of :
    case 7: // Fine, ends with goto case.
        goto case 1;

    case 8:
        break;
        x = 6; // Error: break; must be the last statement for case 8.
}

While I really think the best solution is to just make a goto case required if you want to fall-through [†], it's great to have a patch for a solution. Thanks Chad! =)

[*]

This is the latest discussion about this, started by Chad Joan (I guess): http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=101110

Here is the last minute announcement of the patch: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=101937

And here are some links for older switch statement related discussions:

[†]I find it more readable and with better locality, to know if something fall-through or not I just have to read the code sequentially without remembering which kind of case I'm in. And I think cases without any statements should be allowed too, I wonder how this works with case range statements.