]> git.llucax.com Git - personal/website.git/blob - source/blog/posts/2009/11/20-unintentional-fallthrough-in-d's-switch-statements.rst
Add post
[personal/website.git] / source / blog / posts / 2009 / 11 / 20-unintentional-fallthrough-in-d's-switch-statements.rst
1 Title: Unintentional fall-through in D's switch statements
2 Tags: en, d, patch, switch, fall-through
3
4 Removing switch fall-through from D's switch__ statement is something
5 discussed since the early beginnings of D, there are discussions about it since
6 2001 and to the date [*]_.  If you don't know what I'm talking about, see this
7 example::
8
9     switch (x) {
10     case A:
11         i = x;
12         // fall-through
13     case B:
14         j = 2;
15         break;
16     case C:
17         i = x + 1;
18         break;
19     }
20
21 __ http://www.digitalmars.com/d/2.0/statement.html#SwitchStatement
22
23 .. role:: del
24
25 If you read carefully the :del:`case B` ``case A`` code, it doesn't include
26 a ``break`` statement, so if ``x == A`` not only ``i = x`` will be executed,
27 the code in ``case B`` will be executed too. This is perfectly valid code,
28 introduced by C, but it tends to be very error prone and if you forget
29 a ``break`` statement, the introduced bug can be very hard to track.
30
31 Fall-through if fairly rare, and it would make perfect sense to make it
32 explicit. Several suggestions were made in this time to make fall-through
33 explicit, but nothing materialized yet. Here are the most frequently suggested
34 solutions:
35
36 * Add a new syntax for non-fall-through switch statements, for example::
37
38         switch (x) {
39         case A {
40             i = x;
41         }
42         case B {
43             j = 2;
44         }
45         case C {
46             i = x + 1;
47         }
48
49
50
51 * Don't fall-through by default, use an explicit statement to ask for
52   fall-through, for example::
53
54         switch (x) {
55         case A:
56             i = x;
57             goto case;
58         case B:
59             j = 2;
60             break;
61         case C:
62             i = x + 1;
63             break;
64         }
65
66   Others suggested ``continue switch`` or ``fallthrough``, but I think some
67   of this suggestions were made before ``goto case`` was implemented.
68
69 A few minutes ago, Chad Joan has filled a bug__ with this issue, but with
70 a patch__ attached 8-). He opted for an intermediate solution, more in the
71 lines of new switch syntax. He defines 2 ``case`` statements: ``case X:`` and
72 ``case X!:`` (note the **!**). The former doesn't allow implicit fall-through
73 and the latter does. This is the example in the bug report::
74
75     switch (i)
76     {
77         case 1!: // Intent to use fall through behavior.
78             x = 3;
79         case 2!: // It's OK to decide to not actually fall through.
80             x = 4;
81             break;
82
83         case 3,4,5:
84             x = 5;
85             break;
86
87         case 6: // Error: You either forgot a break; or need to use !: instead of :
88         case 7: // Fine, ends with goto case.
89             goto case 1;
90
91         case 8:
92             break;
93             x = 6; // Error: break; must be the last statement for case 8.
94     }
95
96 __ http://d.puremagic.com/issues/show_bug.cgi?id=3536
97 __ http://d.puremagic.com/issues/attachment.cgi?id=505&action=diff
98
99 While I really think the best solution is to just make a ``goto case`` required
100 if you want to fall-through [*]_, it's great to have a patch for a solution.
101 Thanks Chad! =)
102
103
104 .. [*] This is the latest discussion about this, started by Chad Joan (I guess):
105     http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=101110
106
107     Here is the last minute announcement of the patch:
108     http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=101937
109
110     And here are some links for older switch statement related discussions:
111
112     * http://www.digitalmars.com/d/archives/22722.html
113     * http://www.digitalmars.com/d/archives/154.html
114     * http://www.digitalmars.com/d/archives/10188.html
115     * http://www.digitalmars.com/d/archives/43.html
116     * http://www.digitalmars.com/d/archives/1008.html
117     * http://www.digitalmars.com/d/archives/20149.html
118     * http://www.digitalmars.com/d/archives/10455.html
119     * http://www.digitalmars.com/d/archives/3468.html
120     * http://www.digitalmars.com/d/archives/28287.html
121     * http://www.digitalmars.com/d/archives/17102.html
122     * http://www.digitalmars.com/d/archives/digitalmars/D/11512.html
123     * http://www.digitalmars.com/d/archives/digitalmars/D/switch_break_fall_last_minute_request\_..._45806.html
124     * http://www.digitalmars.com/d/archives/digitalmars/D/Re_No_more_fall_through_in_case_statement_64747.html
125     * http://www.digitalmars.com/d/archives/digitalmars/D/Re_Switch_90745.html
126     * http://www.digitalmars.com/d/archives/digitalmars/D/17497.html
127     * http://www.digitalmars.com/d/archives/digitalmars/D/Finalizing_D2_91034.html
128     * http://www.digitalmars.com/d/archives/digitalmars/D/Go_A_new_system_programing_language_100547.html
129
130 .. [*] I find it more readable and with better *locality*, to know if something
131     fall-through or not I just have to read the code sequentially without
132     remembering which kind of ``case`` I'm in. And I think cases without any
133     statements should be allowed too, I wonder how this works with `case
134     range`__ statements.
135
136 __ http://www.digitalmars.com/d/2.0/statement.html#CaseRangeStatement
137
138 .. vim: set et sw=4 sts=4 :