www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - switch break/fall (last minute request ... )

reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Maybe it's pointless asking this now, five days before v1.0, but I'll 
give it a try.

I would love it if there was a way to let the compiler catch the common 
bug of forgetting a "break" statement after a case clause in a switch 
statement.

The C behavior of automatically falling through is a cause of many many 
bugs. It's really easy to forget a break and it's not really easy to 
discover this bug.

I propose a new keyword, "fall", that would explicitly indicate the 
coder's intention of allowing the switch statement to fall through to 
the next case clause.
The absence of either "fall" or "break" would indicate an error.

Hypothetical example:
------------------
switch( X )
{
   case A:
        //something
        fall;   <-- falls through to the next case
   case B:
        //something
        break;  <-- break, same behavior as now
   case C:
        //something
   case D:      <-- error, no break or fall statement before case D
        //something
        break;
}
-----------------
Dec 25 2006
next sibling parent BCS <BCS pathilink.com> writes:
Hasan Aljudy wrote:
 Maybe it's pointless asking this now, five days before v1.0, but I'll 
 give it a try.
 
 I would love it if there was a way to let the compiler catch the common 
 bug of forgetting a "break" statement after a case clause in a switch 
 statement.
 
 The C behavior of automatically falling through is a cause of many many 
 bugs. It's really easy to forget a break and it's not really easy to 
 discover this bug.
 
 I propose a new keyword, "fall", that would explicitly indicate the 
 coder's intention of allowing the switch statement to fall through to 
 the next case clause.
 The absence of either "fall" or "break" would indicate an error.
 
 Hypothetical example:
 ------------------
 switch( X )
 {
   case A:
        //something
        fall;   <-- falls through to the next case
   case B:
        //something
        break;  <-- break, same behavior as now
   case C:
        //something
   case D:      <-- error, no break or fall statement before case D
        //something
        break;
 }
 -----------------
banning fall through but retaining "goto case;" and "goto case value;" would have the same effect. But for some reason I like your suggestion better. However, I'd rather just leave it all as it is. What we need is a D-lint tool that would could enforce a set of "Optional requirements". (Oh, cool name "D OptiOnal Requirements System", DOORS!!!!).
Dec 25 2006
prev sibling parent reply %u <u digitaldaemon.com> writes:
== Quote from Hasan Aljudy (hasan.aljudy gmail.com)'s article
    case C:
         //something
    case D:      <-- error, no break or fall statement before case
D So:
    case C:
if( b1 ) { fall; break;} else if( b2) goto case C; else { break; fall;}
    case D:
would be legal?
Dec 25 2006
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
%u wrote:
 == Quote from Hasan Aljudy (hasan.aljudy gmail.com)'s article
    case C:
         //something
    case D:      <-- error, no break or fall statement before case
D So:
    case C:
if( b1 ) { fall; break;} else if( b2) goto case C; else { break; fall;}
    case D:
would be legal?
I'm pretty sure this one has been discussed to death in the past, so I doubt any last minute plea is going to change anything, for 1.0 at least. :-) Walter's position previously has been that he didn't want to confuse the poor C/C++/Java converts regardless of how error-prone default fall through is. If you look at the kind of code Walter writes (see parse.c in the DMD source in particular), you'll see that he is quite fond of stacking up multiple case labels, so I doubt he'd ever agree to make case TOKstruct: case TOKunion: case TOKclass: case TOKinterface: s = parseAggregate(); break; an error. However, what if you modify the rule slightly so that if a case follows another case immediately, then a 'fall' is not required? Then Walter may yet find it palatable. I'm all for it, though. I've been debugging my own missing 'break' statements for 20 years now, and I still never seem to learn. --bb
Dec 25 2006
next sibling parent Jason House <jason.james.house gmail.com> writes:
Bill Baxter wrote:
 If you look at the kind of code Walter writes (see parse.c in the DMD 
 source in particular), you'll see that he  is quite fond of stacking up 
 multiple case labels, so I doubt he'd ever agree to make
         case TOKstruct:
         case TOKunion:
         case TOKclass:
         case TOKinterface:
         s = parseAggregate();
         break;
 an error.
 
 However, what if you modify the rule slightly so that if a case follows 
 another case immediately, then a 'fall' is not required?  Then Walter 
 may yet find it palatable.
 
 I'm all for it, though.  I've been debugging my own missing 'break' 
 statements for 20 years now, and I still never seem to learn.
I like this modified suggestion too. Not to confuse the issue, but at least some thought should be given to using the continue keyword instead of a new keyword. The break keyword in switches already conflicts with the break keyword in loops... just like a continue keyword would too. I think the real show stopper is that it could lead to different behavior between C and D. I don't know if any thought has gone into disambiguating the continue (or break) keyword with nested loops. The same thing could be used here.
Dec 26 2006
prev sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Bill Baxter wrote:
 %u wrote:
 == Quote from Hasan Aljudy (hasan.aljudy gmail.com)'s article
    case C:
         //something
    case D:      <-- error, no break or fall statement before case
D So:
    case C:
if( b1 ) { fall; break;} else if( b2) goto case C; else { break; fall;}
    case D:
would be legal?
I'm pretty sure this one has been discussed to death in the past, so I doubt any last minute plea is going to change anything, for 1.0 at least. :-) Walter's position previously has been that he didn't want to confuse the poor C/C++/Java converts regardless of how error-prone default fall through is.
This is so against the philosophy of D. Nothing should be confusing, as the compiler would explicitly state in the error message that either "fall" or "break" must be present. Plus, Already many parts of D would confuse new comers, think about: foreach( item; items ) { ... } // Wait .. where was item defined? void func(X)(X y) { .. } // Wait .. why two sets of parameters? class X(Y) { .. } // Hmm .. is this D's way of defining inheritance? huh? like python?? class D : X { .. } // Hmm .. guess that X(Y) wasn't inheritance class A(B) : B, C, D // Now that's just plain confusing None of these examples is anymore confusing than requiring a "fall" or "break" for switch cases.
 
 If you look at the kind of code Walter writes (see parse.c in the DMD 
 source in particular), you'll see that he  is quite fond of stacking up 
 multiple case labels, so I doubt he'd ever agree to make
         case TOKstruct:
         case TOKunion:
         case TOKclass:
         case TOKinterface:
         s = parseAggregate();
         break;
 an error.
Walter already solved this, in D you can do: case TOKstruct, TOKunion, TOKclass, TOKinterface: s = parseAggregate(); break;
 
 However, what if you modify the rule slightly so that if a case follows 
 another case immediately, then a 'fall' is not required?  Then Walter 
 may yet find it palatable.
 
 I'm all for it, though.  I've been debugging my own missing 'break' 
 statements for 20 years now, and I still never seem to learn.
Thanks for the testimony. I think this is true for *all* C/C++ programmers. I feel that fighting this common source of bug should've been one of the first things that D had done.
 
 --bb
Dec 26 2006
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Hasan Aljudy wrote:
 
 
 Bill Baxter wrote:
 %u wrote:
 == Quote from Hasan Aljudy (hasan.aljudy gmail.com)'s article
    case C:
         //something
    case D:      <-- error, no break or fall statement before case
D So:
    case C:
if( b1 ) { fall; break;} else if( b2) goto case C; else { break; fall;}
    case D:
would be legal?
I'm pretty sure this one has been discussed to death in the past, so I doubt any last minute plea is going to change anything, for 1.0 at least. :-) Walter's position previously has been that he didn't want to confuse the poor C/C++/Java converts regardless of how error-prone default fall through is.
This is so against the philosophy of D. Nothing should be confusing, as the compiler would explicitly state in the error message that either "fall" or "break" must be present.
I didn't really get his argument either, so it's possible my paraphrasing of it somehow missed his real point. Or maybe it's just that he didn't like the idea of changing it to the point where 'break' was implicit and a fall-through keyword was required. But with your suggestion, as you say, the compiler will tell you if you're falling into C/C++ habits.
 Plus, Already many parts of D would confuse new comers, think about:
 
 foreach( item; items ) { ... } // Wait .. where was item defined?
 
 void func(X)(X y) { .. } // Wait .. why two sets of parameters?
 
 class X(Y) { .. } // Hmm .. is this D's way of defining inheritance? 
 huh? like python??
 
 class D : X { .. } // Hmm .. guess that X(Y) wasn't inheritance
 
 class A(B) : B, C, D // Now that's just plain confusing
 
 None of these examples is anymore confusing than requiring a "fall" or 
 "break" for switch cases.
 
 If you look at the kind of code Walter writes (see parse.c in the DMD 
 source in particular), you'll see that he  is quite fond of stacking 
 up multiple case labels, so I doubt he'd ever agree to make
         case TOKstruct:
         case TOKunion:
         case TOKclass:
         case TOKinterface:
         s = parseAggregate();
         break;
 an error.
Walter already solved this, in D you can do: case TOKstruct, TOKunion, TOKclass, TOKinterface: s = parseAggregate(); break;
I didn't realize that worked. =) Actually I was thinking to suggest that, but figured that was a bigger lump of coal to swallow than just allowing adjacent cases to fall through. :-)
 However, what if you modify the rule slightly so that if a case 
 follows another case immediately, then a 'fall' is not required?  Then 
 Walter may yet find it palatable.

 I'm all for it, though.  I've been debugging my own missing 'break' 
 statements for 20 years now, and I still never seem to learn.
Thanks for the testimony. I think this is true for *all* C/C++ programmers. I feel that fighting this common source of bug should've been one of the first things that D had done.
I agree. I think it was one of the first things that came to my mind when first looking into D, when I read the mantra on the D intro page about fixing design flaws in C/C++. "Oh great, that must mean the switch/break debacle is fixed ... hmm and what else I wonder". Come to find out that my first guess was wrong. --bb (P.S. This still ain't gonna happen in the next 3 days. ;-))
Dec 26 2006
prev sibling parent reply mike <vertex gmx.at> writes:
Am 26.12.2006, 23:26 Uhr, schrieb Hasan Aljudy <hasan.aljudy gmail.com>:=


 I feel that fighting this common source of bug should've been one of t=
he =
 first things that D had done.
I've once suggested this syntax: ' switch (foo) ' { ' case (0) writefln("one statement for case 0"); <-- doesn't fall = through ' case (1) ' { ' writefln("case 1"); ' writefln("has two statements"); ' } ' case (2, 3) ' { ' writefln("case 2 or case 3"); ' writefln("falls through to case 4); ' continue 4; ' } ' case (4) ' { ' writefln("case 4"); ' if (foo =3D=3D 2) break; // <-- break still breaks out of the = switch ' writefln("not case 2"); ' } ' else writefln("switch default"); ' } Still would like that better than the C syntax (and it saves a keyword!)= , = but, anyway: If you write the break as soon as you write the case label = = and then insert the code you'll never forget the break. This works, this= = way I never forgot a break in years. -mike -- = Erstellt mit Operas revolution=E4rem E-Mail-Modul: http://www.opera.com/= mail/
Dec 26 2006
parent "Craig Black" <cblack ara.com> writes:
I like this syntax.  It fits better with the rest of the language.  However, 
it's too different, so I don't think Walter would go for it.

-Craig

"mike" <vertex gmx.at> wrote in message news:op.tk6yflzgnxkcto zimmermoos...
Am 26.12.2006, 23:26 Uhr, schrieb Hasan Aljudy <hasan.aljudy gmail.com>:

 I feel that fighting this common source of bug should've been one of the 
 first things that D had done.
I've once suggested this syntax: ' switch (foo) ' { ' case (0) writefln("one statement for case 0"); <-- doesn't fall through ' case (1) ' { ' writefln("case 1"); ' writefln("has two statements"); ' } ' case (2, 3) ' { ' writefln("case 2 or case 3"); ' writefln("falls through to case 4); ' continue 4; ' } ' case (4) ' { ' writefln("case 4"); ' if (foo == 2) break; // <-- break still breaks out of the switch ' writefln("not case 2"); ' } ' else writefln("switch default"); ' } Still would like that better than the C syntax (and it saves a keyword!), but, anyway: If you write the break as soon as you write the case label and then insert the code you'll never forget the break. This works, this way I never forgot a break in years. -mike -- Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/
Dec 27 2006