www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Inside the switch statement

reply Sam Hu <samhudotsamhu gmail.com> writes:
To save time ,just get to my point:I do not understand why such code below
inside the switch ... case statement is allowed ,what is the point of do ...
while...:

This example uses a mixin to implement a generic Duff's device for an arbitrary
statement (in this case, the arbitrary statement is in bold). A nested function
is generated as well as a delegate literal, these can be inlined by the
compiler: 
template duffs_device(alias id1, alias id2, alias s)
{
    void duff_loop()
    {
	if (id1 < id2)
	{
	    typeof(id1) n = (id2 - id1 + 7) / 8;
	    switch ((id2 - id1) % 8)
	    {
		case 0:        do {  s();
		case 7:              s();
		case 6:              s();
		case 5:              s();
		case 4:              s();
		case 3:              s();
		case 2:              s();
		case 1:              s();
				  } while (--n > 0);
	    }
	}
    }
}

void foo() { writefln("foo"); }

void test()
{
    int i = 1;
    int j = 11;

    mixin duffs_device!(i, j, delegate { foo(); } );
    duff_loop();	// executes foo() 10 times
}

Thanks in advance.

Regards,
Sam
Jun 08 2009
next sibling parent reply BCS <none anon.com> writes:
Hello Sam,

 To save time ,just get to my point:I do not understand why such code
 below inside the switch ... case statement is allowed ,what is the
 point of do ... while...:
This is a classic C thing. The short explanation is that a switch is a conditional, many way goto and the labels can be *anywhere* in the body (except inside another switch). For the more in depth version Google "duff's device".
 
 This example uses a mixin to implement a generic Duff's device for an
 arbitrary statement (in this case, the arbitrary statement is in
 bold).
BTW: where is this from?
 A nested function is generated as well as a delegate literal,
 these can be inlined by the compiler:
 template duffs_device(alias id1, alias id2, alias s)
 {
 void duff_loop()
 {
 if (id1 < id2)
 {
 typeof(id1) n = (id2 - id1 + 7) / 8;
 switch ((id2 - id1) % 8)
 {
 case 0:        do {  s();
 case 7:              s();
 case 6:              s();
 case 5:              s();
 case 4:              s();
 case 3:              s();
 case 2:              s();
 case 1:              s();
 } while (--n > 0);
 }
 }
 }
 }
 void foo() { writefln("foo"); }
 
 void test()
 {
 int i = 1;
 int j = 11;
 mixin duffs_device!(i, j, delegate { foo(); } );
 duff_loop();	// executes foo() 10 times
 }
Jun 08 2009
next sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
BCS wrote:
 Hello Sam,
 
 To save time ,just get to my point:I do not understand why such code
 below inside the switch ... case statement is allowed ,what is the
 point of do ... while...:
This is a classic C thing. The short explanation is that a switch is a conditional, many way goto and the labels can be *anywhere* in the body (except inside another switch). For the more in depth version Google "duff's device".
 This example uses a mixin to implement a generic Duff's device for an
 arbitrary statement (in this case, the arbitrary statement is in
 bold).
BTW: where is this from?
I would guess from the D specs http://www.digitalmars.com/d/1.0/template-mixin.html
Jun 08 2009
prev sibling parent reply Sam Hu <samhudotsamhu gmail.com> writes:
Thanks so much for all your help!I am studying hard to *loop unrolling*.

 BTW: where is this from?
It is from the spec: http://www.digitalmars.com/d/1.0/template-mixin.html BTW,is this Duff? http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
Jun 08 2009
parent reply grauzone <none example.net> writes:
 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
Many people (even Brian Kernighan?) have said that the worst feature 
of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
Jun 09 2009
parent reply BCS <none anon.com> writes:
Hello grauzone,

 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
 
Many people (even Brian Kernighan?) have said that the worst feature of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
I'm sorry, you don't have my sympathy on this one. There are to many place I've used fall throught to chuck it out.
Jun 09 2009
next sibling parent reply grauzone <none example.net> writes:
BCS wrote:
 Hello grauzone,
 
 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
Many people (even Brian Kernighan?) have said that the worst feature of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
I'm sorry, you don't have my sympathy on this one. There are to many place I've used fall throught to chuck it out.
What kind of fall-throughs were these? A: case value1: case value2: case valueN: code1(); break; B: case value1: code1(); case value2: code2(); break;
Jun 09 2009
next sibling parent BCS <none anon.com> writes:
Hello grauzone,

 BCS wrote:
 
 Hello grauzone,
 
 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
 
Many people (even Brian Kernighan?) have said that the worst feature of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
I'm sorry, you don't have my sympathy on this one. There are to many place I've used fall throught to chuck it out.
What kind of fall-throughs were these? A: case value1: case value2: case valueN: code1(); break;
I don't do that, I go with this form: case value1, value2, valueN: code1(); break; case B, The most usefull case was where I used the switch as a "jump into the middle of this block of code" device.
 B:
 
 case value1:
 code1();
 case value2:
 code2();
 break;
Jun 09 2009
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
grauzone wrote:
 BCS wrote:
 Hello grauzone,

 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
Many people (even Brian Kernighan?) have said that the worst feature of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
I'm sorry, you don't have my sympathy on this one. There are to many place I've used fall throught to chuck it out.
What kind of fall-throughs were these? A: case value1: case value2: case valueN: code1(); break; B: case value1: code1(); case value2: code2(); break;
The solution is to forbid fallthrough, and change the switch syntax: switch(value) { case 1: case 2: // something break; } gives: Error, missing break at the end of case1. But: switch(value) { case 1, 2: // something break; } works as expected. What's wrong with that?
Jun 09 2009
parent reply "Saaa" <empty needmail.com> writes:
 What kind of fall-throughs were these?

 A:

 case value1:
 case value2:
 case valueN:
     code1();
     break;

 B:

 case value1:
     code1();
 case value2:
     code2();
     break;
The solution is to forbid fallthrough, and change the switch syntax: switch(value) { case 1: case 2: // something break; } gives: Error, missing break at the end of case1. But: switch(value) { case 1, 2: // something break; } works as expected. What's wrong with that?
Doesn't support B :) How about a warning instead?
Jun 09 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
 What kind of fall-throughs were these?

 A:

 case value1:
 case value2:
 case valueN:
     code1();
     break;

 B:

 case value1:
     code1();
 case value2:
     code2();
     break;
The solution is to forbid fallthrough, and change the switch syntax: switch(value) { case 1: case 2: // something break; } gives: Error, missing break at the end of case1. But: switch(value) { case 1, 2: // something break; } works as expected. What's wrong with that?
Doesn't support B :) How about a warning instead?
The idea is that it not supporting B is something good. An error is ok, and if you want to translate C code then it's really easy to change the code to not give errors.
Jun 09 2009
parent reply "Saaa" <empty needmail.com> writes:
 What's wrong with that?
Doesn't support B :) How about a warning instead?
The idea is that it not supporting B is something good.
I know this is your idea, but as BCS doesn't support this idea. You should have replied to him iso grauzone. I personally never had any problems with falling through. The IDE ( descent :) indents it nicely.
 An error is ok, and if you want to translate C code then it's really easy 
 to change the code to not give errors.
I don't think you will get that, thus maybe a warning is better than nothing?
Jun 09 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
 What's wrong with that?
Doesn't support B :) How about a warning instead?
The idea is that it not supporting B is something good.
I know this is your idea, but as BCS doesn't support this idea.
How do you know? BCS didn't reply to my idea.
 You should have replied to him iso grauzone.
 
 I personally never had any problems with falling through.
 The IDE  ( descent :) indents it nicely.
 
 
 An error is ok, and if you want to translate C code then it's really easy 
 to change the code to not give errors.
I don't think you will get that, thus maybe a warning is better than nothing?
A warning *is* nothing. :-P
Jun 09 2009
parent reply "Saaa" <empty needmail.com> writes:
 How do you know? BCS didn't reply to my idea.
Your idea was to give an error on the case (B) he uses. Or did I miss something?
Jun 09 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
 How do you know? BCS didn't reply to my idea.
Your idea was to give an error on the case (B) he uses. Or did I miss something?
You missed the alternative syntax to get the same behaviour. But it's a very subtle difference.
Jun 09 2009
parent reply "Saaa" <empty needmail.com> writes:
 You missed the alternative syntax to get the same behaviour. But it's a 
 very subtle difference.
Do you mean the multiple cases? http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement
Jun 09 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
 You missed the alternative syntax to get the same behaviour. But it's a 
 very subtle difference.
Do you mean the multiple cases? http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement
Yes, but make the "multiple cases" the *only* way to make case statements fallthrough. That would be the change.
Jun 09 2009
next sibling parent reply "Saaa" <empty needmail.com> writes:
 Yes, but make the "multiple cases" the *only* way to make case
 statements fallthrough. That would be the change.
That is the same as giving an error on case B, right?
Jun 09 2009
next sibling parent "Saaa" <empty needmail.com> writes:
I mean, the syntax stays the same. 
Jun 09 2009
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
 Yes, but make the "multiple cases" the *only* way to make case
 statements fallthrough. That would be the change.
That is the same as giving an error on case B, right?
Well, yes, but you also have to prepare your mind for the change. This is a huge step. (nah, just kidding, you're right, I didn't realize it :-P)
Jun 09 2009
next sibling parent "Saaa" <empty needmail.com> writes:
 Well, yes, but you also have to prepare your mind for the change. This
 is a huge step.
;)
Jun 09 2009
prev sibling parent reply "Saaa" <empty needmail.com> writes:
 (nah, just kidding, you're right, I didn't realize it :-P)

Ok, enough kidding around, lets get back to you helping me with 'code 
generalization' :P 
Jun 09 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Saaa wrote:
  (nah, just kidding, you're right, I didn't realize it :-P)
 
 Ok, enough kidding around, lets get back to you helping me with 'code 
 generalization' :P
Write a lexer and a parser.
Jun 09 2009
parent "Saaa" <empty needmail.com> writes:
 Write a lexer and a parser.
how do you mean?
Jun 09 2009
prev sibling parent BCS <none anon.com> writes:
Hello Ary,

 Saaa wrote:
 
 You missed the alternative syntax to get the same behaviour. But
 it's a very subtle difference.
 
Do you mean the multiple cases? http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement
Yes, but make the "multiple cases" the *only* way to make case statements fallthrough. That would be the change.
that /does not/ support the use case I have used: switch(n) { case 1: some_func(); case 2: some_other_func(); }
Jun 09 2009
prev sibling parent Steve Schveighoffer <schveiguy yahoo.com> writes:
On Tue, 09 Jun 2009 19:35:51 +0200, Saaa wrote:

 What kind of fall-throughs were these?

 A:

 case value1:
 case value2:
 case valueN:
     code1();
     break;

 B:

 case value1:
     code1();
 case value2:
     code2();
     break;
The solution is to forbid fallthrough, and change the switch syntax: switch(value) { case 1: case 2: // something break; } gives: Error, missing break at the end of case1. But: switch(value) { case 1, 2: // something break; } works as expected. What's wrong with that?
Doesn't support B :)
case value1: code1(); goto case value2; // already valid D code // or goto case; // already valid D code case value2: code2(); break; Should be uncommon enough that the extra clarification is warranted IMO. I believe I've fallen victim to accidental fall-throughs more than I've found uses for them... vote++ -Steve
Jun 10 2009
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 9 Jun 2009 16:28:58 +0000 (UTC), BCS wrote:

 Hello grauzone,
 
 http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
 
Many people (even Brian Kernighan?) have said that the worst feature of C is that switches don't break automatically before each case label. Oh god, that's from 1984, and even today we're struggling with this bullshit in the most modern dialect of C, D.
I'm sorry, you don't have my sympathy on this one. There are to many place I've used fall throught to chuck it out.
It is not an either-or situation. We achieved both models in the up-coming version of Euphoria, at the minor cost of a new keyword. By default, it does not do fallthru. Each case is its own master and the physical placement inside the switch is not relevant. switch EXPR do case VAL1 then STATEMENTS... case VAL2 then STATEMENTS... case VAL3 then STATEMENTS... end switch But, if for some good reason you need to do fallthru ... switch EXPR with fallthru do case VAL1 then STATEMENTS... case VAL2 then STATEMENTS... case VAL3 then STATEMENTS... end switch It that situation, the absence of a 'break' means that program flow falls through to the next case. You can still insert 'break' at any point to skip to the end of the switch statement, even in the default format. However, additionally in the default format you can use 'fallthru' to let flow drop to the next case.... switch EXPR do case VAL1 then STATEMENTS... case VAL2 then STATEMENTS... fallthru -->>> This makes flow fall through. case VAL3 then STATEMENTS... end switch So, if one considers improving D's switch, it is possible to have both models if one is not frightened of new keywords. For example ... select (EXPR) { case VAL1: STATEMENTS... case VAL2: STATEMENTS... case VAL3: STATEMENTS... } would only execute ONE of the selected cases. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Jun 09 2009
parent BCS <none anon.com> writes:
Hello Derek,

 On Tue, 9 Jun 2009 16:28:58 +0000 (UTC), BCS wrote:
 
 I'm sorry, you don't have my sympathy on this one. There are to many
 place I've used fall throught to chuck it out.
[...]
 However, additionally in the default format you can use
 'fallthru' to let flow drop to the next case....
 
 switch EXPR do
 case VAL1 then
 STATEMENTS...
 case VAL2 then
 STATEMENTS...
 fallthru  -->>> This makes flow fall through.
 case VAL3 then
 STATEMENTS...
 end switch
 So, if one considers improving D's switch, it is possible to have both
 models if one is not frightened of new keywords.
 
 For example ...
 
 select (EXPR) {
 case VAL1:
 STATEMENTS...
 case VAL2:
 STATEMENTS...
 case VAL3:
 STATEMENTS...
 }
 would only execute ONE of the selected cases.
 
any generic "goto next" ability and I would find that very painful in some template code.
Jun 09 2009
prev sibling parent reply Kagamin <spam here.lot> writes:
 template duffs_device(alias id1, alias id2, alias s)
 {
     void duff_loop()
     {
 	if (id1 < id2)
 	{
 	    typeof(id1) n = (id2 - id1 + 7) / 8;
 	    switch ((id2 - id1) % 8)
 	    {
 		case 0:        do {  s();
 		case 7:              s();
 		case 6:              s();
 		case 5:              s();
 		case 4:              s();
 		case 3:              s();
 		case 2:              s();
 		case 1:              s();
 				  } while (--n > 0);
 	    }
 	}
     }
 }
 
 void foo() { writefln("foo"); }
 
 void test()
 {
     int i = 1;
     int j = 11;
 
     mixin duffs_device!(i, j, delegate { foo(); } );
     duff_loop();	// executes foo() 10 times
 }
The Duff's device is said to be an optimization, but I get blunt device only 0.7% slower. template blunt_device(alias id1, alias id2, alias s) { void blunt_loop() { if (id1 < id2) { typeof(id1) i = id2 - id1; while(i-->0)s(); } } }
Jun 11 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Kagamin:
 The Duff's device is said to be an optimization, but I get blunt device only
0.7% slower.
Compilers already know about the Duff's device, and sometimes they use it automatically. Bye, bearophile
Jun 11 2009
prev sibling parent "Joel C. Salomon" <joelcsalomon gmail.com> writes:
Kagamin wrote:
 The Duff's device is said to be an optimization, but I get blunt device only
0.7% slower.
Read Duff’s post: “this loop was the bottleneck in a real-time animation playback program”, and all the Device is doing is unwinding the loop a few times. Optimization comes because — on the particular system the code was written for — the eight-times-unwound loop fit nicely into cache. —Joel Salomon
Jun 15 2009