www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What is the use case for this weird switch mecanism

reply deadalnix <deadalnix gmail.com> writes:
Today, I noticed by digging into D details the following construct :

switch(foo) {
     statement;
     case A:
         // Stuffs . . .

     // Other cases.
     default:
         // Stuffs . . .
}

What the hell statement is supposed to do ? And what is the use case for 
this ?
Oct 30 2012
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Oct 30, 2012 at 05:16:48PM +0100, deadalnix wrote:
 Today, I noticed by digging into D details the following construct :
 
 switch(foo) {
     statement;
     case A:
         // Stuffs . . .
 
     // Other cases.
     default:
         // Stuffs . . .
 }
 
 What the hell statement is supposed to do ? And what is the use case
 for this ?
That's weird. I just did a quick test; apparently statement is never run. I've no idea why it's allowed or what it's for. T -- Debian GNU/Linux: Cray on your desktop.
Oct 30 2012
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
 What the hell statement is supposed to do ? And what is the use case
 for this ?
That's weird. I just did a quick test; apparently statement is never run. I've no idea why it's allowed or what it's for.
I've no idea why it's authorized, but it saved my day a week ago, in an automatically-generated switch statement that happened to have a "return true;" inserted at the very beginning. No unit test found that and I saw it only by printing the generated code for another search. In a way, it's logical: the code path jumps to the matching case, so it never sees the first statement block before the first case.
Oct 30 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 30/10/2012 18:47, Philippe Sigaud a écrit :
 What the hell statement is supposed to do ? And what is the use case
 for this ?
That's weird. I just did a quick test; apparently statement is never run. I've no idea why it's allowed or what it's for.
I've no idea why it's authorized, but it saved my day a week ago, in an automatically-generated switch statement that happened to have a "return true;" inserted at the very beginning. No unit test found that and I saw it only by printing the generated code for another search. In a way, it's logical: the code path jumps to the matching case, so it never sees the first statement block before the first case.
I usually want to avoid code working in an unexpected way. Even when it make code work when I expect it shouldn't. I wrote about this publicly few mounth ago, and, considering how much return I got, I'm not the only one.
Oct 30 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
deadalnix:

 What the hell statement is supposed to do ? And what is the use 
 case for this ?
See also this bug report I've opened time ago: http://d.puremagic.com/issues/show_bug.cgi?id=3820 Bye, bearophile
Oct 30 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/30/12, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 I've no idea why it's authorized
There could be a label for a goto there.
Oct 30 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 30/10/2012 18:57, Andrej Mitrovic a écrit :
 On 10/30/12, Philippe Sigaud<philippe.sigaud gmail.com>  wrote:
 I've no idea why it's authorized
There could be a label for a goto there.
That still don't explain what the use case is.
Oct 30 2012
parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Tue, 30 Oct 2012 21:39:31 +0100
deadalnix <deadalnix gmail.com> wrote:

 Le 30/10/2012 18:57, Andrej Mitrovic a =E9crit :
 On 10/30/12, Philippe Sigaud<philippe.sigaud gmail.com>  wrote:
 I've no idea why it's authorized
There could be a label for a goto there.
=20 That still don't explain what the use case is.
Obfuscated coding contests?
Oct 30 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Nick Sabalausky:

 Obfuscated coding contests?
It's there to help programmers create more bugs, of course :o) Bye, bearophile
Oct 30 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Tuesday, 30 October 2012 at 21:11:57 UTC, bearophile wrote:
 Nick Sabalausky:

 Obfuscated coding contests?
It's there to help programmers create more bugs, of course :o)
Maybe variable declaration (as long as they are default(s))? Has a certain amount of sense, but makes more sense to do it outside the switch case...
Oct 30 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Era Scarecrow:

  Maybe variable declaration (as long as they are default(s))? 
 Has a certain amount of sense, but makes more sense to do it 
 outside the switch case...
Declaring variables there is dangerous: import std.stdio; struct Foo { int x = 10; } void main() { int bar; switch(bar) { Foo f; case 10: break; default: writeln(f); // prints garbage } } Bye, bearophile
Oct 30 2012
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Tuesday, 30 October 2012 at 21:40:26 UTC, bearophile wrote:
 Era Scarecrow:
 Maybe variable declaration (as long as they are default(s))?
Declaring variables there is dangerous:
     switch(bar) {
         Foo f;
         case 10: break;
         default: writeln(f); // prints garbage
     }
Then it's as though it were '= void;' by default. Most curious. Honestly I'd say it's illegal to have something before any callable case; Besides for goto's it's illegal to jump past declarations, yet this switch case allows it. I'd say one of two things must happen then. 1) Code before the first case is disallowed 2) Code before the first case always runs Option 2 seems silly and unneeded, except it allows a small scope during the switch call, which is it's only possible advantage. The only other advantage is you could have a case disabled and enable it during certain debugging cases, but in those cases why not do the whole block?
     switch(bar) {
static if (DEBUG) { case -10: /*disabled case, or something like that*/ } Foo f;
         case 10: break;
Oct 30 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Oct 30, 2012 at 04:51:33PM -0400, Nick Sabalausky wrote:
 On Tue, 30 Oct 2012 21:39:31 +0100
 deadalnix <deadalnix gmail.com> wrote:
 
 Le 30/10/2012 18:57, Andrej Mitrovic a écrit :
 On 10/30/12, Philippe Sigaud<philippe.sigaud gmail.com>  wrote:
 I've no idea why it's authorized
There could be a label for a goto there.
That still don't explain what the use case is.
Obfuscated coding contests?
Is this the official announcement for the inception of the IODCC? ;-) (cf. www.ioccc.org). T -- Those who've learned LaTeX swear by it. Those who are learning LaTeX swear at it. -- Pete Bleackley
Oct 30 2012
prev sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"deadalnix" <deadalnix gmail.com> wrote in message 
news:k6ouhh$116v$1 digitalmars.com...
 Today, I noticed by digging into D details the following construct :

 [snip switch being stupid]

 What the hell statement is supposed to do ? And what is the use case for 
 this ?
The structure for switch is: switch(value) Statement(s) There is very little structure imposed on the statements it contains. If there are any case or default labels inside the switch that are not inside another inner switch, they are linked to the value and can be jumped to. One (the only?) use case for the loose definition is Duff's Device. The reason it's like this in D: that's how it is in C.
Oct 30 2012
parent reply "Chris Nicholson-Sauls" <ibisbasenji gmail.com> writes:
Some related actual code from a while back:


ParseTree prune ( ParseTree p ) {
     p.children = p.children.dup;
     foreach ( ref child ; p.children ) {
         child = prune( child );
     }

     switch ( p.ruleName ) {
         // strip prefix/suffix terminals, then if left with only 
one child, skip over it
         case "Args"             :
         case "List"             :
         case "Params"           :
         case "Table"            :   p.children = p.children[ 1 .. 
$ - 1 ];
                                     if ( p.children.length == 1 ) 
{

         // skip over immediate child (always a "Series")
         case "QualIdent"        :
         case "Type"             :       p.children = p.children[ 
0 ].children;
                                     }
                                     break;

         // skip self if it has exactly one child
         case "Addition"         :
         case "BoolAnd"          :
         case "BoolOr"           :
         case "Comparison"       :
         case "Conditional"      :
         case "MaybeParens"      :
         case "Multiplication"   :
         case "Postfix"          :
         case "Primary"          :
         case "Unary"            :   if ( p.children.length == 1 ) 
{

         // skip self
         case "Expression"       :
         case "Field"            :
         case "Ident"            :
         case "Literal"          :
         case "PathElem"         :
         case "Statement"        :       p = p.children[ 0 ];
                                     }
                                     break;

         default:
     }

     return p;
}


Without the loosely defined switch() statement syntax, this would 
have been a royal pain to piece together.  Especially when each 
block of cases was evolving over time.

There is also the trick of doing 'switch(val) with(EnumType) 
{...}' to bring an enum's members into scope so that cases can be 
written as 'case Foo:' rather than 'case EnumType.Foo:'.

-- Chris Nicholson-Sauls
Oct 31 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Chris Nicholson-Sauls:

 There is also the trick of doing 'switch(val) with(EnumType) 
 {...}'
What about writing with(EnumType) switch(val) {...} ? Bye, bearophile
Oct 31 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 31 October 2012 at 22:01:36 UTC, bearophile wrote:
 Chris Nicholson-Sauls:

 There is also the trick of doing 'switch(val) with(EnumType) 
 {...}'
What about writing with(EnumType) switch(val) {...} ?
Maybe... But a problem arises when it's function wide, and should be able to replace (hopefully) any block. Assuming there's no syntactical issues that may break other code. int func() with(EnumType) { //won't compile } int func() { with(EnumType) { //compiles but seems excessive when it doesn't need to... } } But 'switch with' seems the proper way to put it in my mind.
Oct 31 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Era Scarecrow:

  But 'switch with' seems the proper way to put it in my mind.
It's not worth the unsafety of the whole switch. Bye, bearophile
Oct 31 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 31 October 2012 at 22:58:32 UTC, bearophile wrote:
 Era Scarecrow:
 But 'switch with' seems the proper way to put it in my mind.
It's not worth the unsafety of the whole switch.
What? I'd need a little explanation what you'd mean. besides, 'switch with' and 'with switch' are practically identical... aren't they?
Oct 31 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
Era Scarecrow:

 It's not worth the unsafety of the whole switch.
What? I'd need a little explanation what you'd mean.
I meant that semantically clean language features help avoid troubles later while you program :-)
 besides, 'switch with' and 'with switch' are practically
 identical... aren't they?
Yeah, they are practically identical, that's my point. But 'with switch' allows you to to not allow code after the switch, so allows to keep switch syntax cleaner :-) Bye, bearophile
Nov 05 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 31/10/2012 21:33, Chris Nicholson-Sauls a écrit :
 Some related actual code from a while back:


 ParseTree prune ( ParseTree p ) {
 p.children = p.children.dup;
 foreach ( ref child ; p.children ) {
 child = prune( child );
 }

 switch ( p.ruleName ) {
 // strip prefix/suffix terminals, then if left with only one child, skip
 over it
 case "Args" :
 case "List" :
 case "Params" :
 case "Table" : p.children = p.children[ 1 .. $ - 1 ];
 if ( p.children.length == 1 ) {

 // skip over immediate child (always a "Series")
 case "QualIdent" :
 case "Type" : p.children = p.children[ 0 ].children;
 }
 break;

 // skip self if it has exactly one child
 case "Addition" :
 case "BoolAnd" :
 case "BoolOr" :
 case "Comparison" :
 case "Conditional" :
 case "MaybeParens" :
 case "Multiplication" :
 case "Postfix" :
 case "Primary" :
 case "Unary" : if ( p.children.length == 1 ) {

 // skip self
 case "Expression" :
 case "Field" :
 case "Ident" :
 case "Literal" :
 case "PathElem" :
 case "Statement" : p = p.children[ 0 ];
 }
 break;

 default:
 }

 return p;
 }


 Without the loosely defined switch() statement syntax, this would have
 been a royal pain to piece together. Especially when each block of cases
 was evolving over time.

 There is also the trick of doing 'switch(val) with(EnumType) {...}' to
 bring an enum's members into scope so that cases can be written as 'case
 Foo:' rather than 'case EnumType.Foo:'.

 -- Chris Nicholson-Sauls
Wow this is not actually the case presented in y first post, but still very interesting.
Nov 05 2012