digitalmars.D.learn - Inside the switch statement
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
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
}
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
Thanks so much for all your help!I am studying hard to *loop unrolling*.
BTW: where is this from?
http://www.digitalmars.com/d/1.0/template-mixin.html
BTW,is this Duff?
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
Many people (even Brian Kernighan?) have said that the worst feature
Oh god, that's from 1984, and even today we're struggling with this
bullshit in the most modern dialect of C, D.
Hello grauzone,
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
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.
BCS wrote:
Hello grauzone,
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
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;
Hello grauzone,
BCS wrote:
Hello grauzone,
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
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.
place I've used fall throught to chuck it out.
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;
grauzone wrote:
BCS wrote:
Hello grauzone,
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
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?
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?
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;
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.
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.
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?
Saaa wrote:
What's wrong with that?
How about a warning instead?
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
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?
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.
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
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.
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?
I mean, the syntax stays the same.
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)
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)
Ok, enough kidding around, lets get back to you helping me with 'code
generalization' :P
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.
Write a lexer and a parser.
how do you mean?
Hello Ary,
Saaa wrote:
You missed the alternative syntax to get the same behaviour. But
it's a very subtle difference.
http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement
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();
}
On Tue, 9 Jun 2009 16:28:58 +0000 (UTC), BCS wrote:
Hello grauzone,
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c
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
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.
C# sort of takes this approach (by using goto case EXP;) but doesn't have
any generic "goto next" ability and I would find that very painful in some
template code.
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
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();
}
}
}
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
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
|