www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is there ANY chance we can fix the bitwise operator precedence rules?

reply Don <nospam nospam.com> writes:
In the comments for bug 4077, "Bugs caused by bitwise operator precedence"
it was asked why C gave & with lower precedence than ==, when it is 
unintuitive and a frequent source of bugs.

I was quite shocked to find that the reason is backwards compatibility 
with the B programming language.

Denis Ritchie says (http://cm.bell-labs.com/cm/cs/who/dmr/chist.html):
--------------------
At the suggestion of Alan Snyder, I introduced the && and || operators 
to make the mechanism [[short circuit evaluation]] more explicit.

Their tardy introduction explains an infelicity of C's precedence rules. 
In B one writes

     if (a==b & c) ...

to check whether a equals b and c is non-zero; in such a conditional 
expression it is better that & have lower precedence than ==. In 
converting from B to C, one wants to replace & by && in such a 
statement; to make the conversion less painful, we decided to keep the 
precedence of the & operator the same relative to ==, and merely split 
the precedence of && slightly from &. Today, it seems that it would have 
been preferable to move the relative precedences of & and
==, and thereby simplify a common C idiom: to test a masked value 
against another value, one must write

     if ((a&mask) == b) ...

where the inner parentheses are required but easily forgotten.
-----------------------------------
Tragic. Can we end this madness?

Could we give & | ^ the same precedence as ==, making
(a & mask == b) an error, just as (a < b == c) is rejected?
That way we could lay this common bug to rest. I've personally lost days 
of my life to this one. It's a bug 100% of the time.

Or is too late to break backwards compatibility with B ?

BTW I think this a great cautionary tale about the dangers of rating 
backwards compatibility too highly.
Jun 18 2010
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Don <nospam nospam.com> wrote:

 I was quite shocked to find that the reason is backwards compatibility  
 with the B programming language.

Surely it is important that all B code ported to D compiles correctly? :p But yes, end the madness. I fear Walter will only do it if it provably breaks no code, though. I just thought through this agin. WTF? -- Simen
Jun 18 2010
prev sibling next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 18-06-2010 o 23:11:43 Simen kjaeraas <simen.kjaras gmail.com>  =

napisa=B3(a):

 But yes, end the madness. I fear Walter will only do it if it provably=

 breaks no code, though.

if (a=3D=3Db & c) would be flagged as error. If it breaks loudly, that's= ok. = Besides, it's not much used anyway. Ban it. Tomek
Jun 18 2010
parent BCS <none anon.com> writes:
Hello Tomek,

 Dnia 18-06-2010 o 23:11:43 Simen kjaeraas <simen.kjaras gmail.com>
 napisał(a):
 
 But yes, end the madness. I fear Walter will only do it if it
 provably breaks no code, though.
 

ok. Besides, it's not much used anyway. Ban it.

vote++;
 Tomek
 

... <IXOYE><
Jun 19 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
[snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely. A perhaps little known thing is that D doesn't allow this: int a, b, c; if (a < b < c) { ... } although it's compilable code in C. The same strategy could be used for combinations of badly-prioritized operators: the language could just require the user to add parens. Andrei
Jun 18 2010
parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.
 
 A perhaps little known thing is that D doesn't allow this:
 
 int a, b, c;
 if (a < b < c) { ... }
 
 although it's compilable code in C. The same strategy could be used for 
 combinations of badly-prioritized operators: the language could just 
 require the user to add parens.
 
 
 Andrei

Jun 19 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

You may want to make sure Walter approves first. He's the BDFL! Andrei
Jun 19 2010
parent reply Justin Johansson <no spam.com> writes:
Andrei Alexandrescu wrote:
 On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

You may want to make sure Walter approves first. He's the BDFL! Andrei

BDFL = ? Some lame acronym letter tries: B = benevolent D = dictator F = <nullable/> L = language
Jun 19 2010
parent reply BCS <none anon.com> writes:
Hello Justin,


 

Some lame acronym letter tries: B = benevolent D = dictator

F = for ?
 L = language

... <IXOYE><
Jun 19 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/19/2010 10:17 AM, BCS wrote:
 Hello Justin,



Some lame acronym letter tries: B = benevolent D = dictator

F = for ?
 L = language


http://en.wikipedia.org/wiki/Benevolent_Dictator_For_Life Andrei
Jun 19 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

Walter just gave the green light, so Don - it's up to you. He also agreed to give more thought to the restriction of forcing every swich label to be ended with a control flow transfer statement. Andrei
Jun 20 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 Walter just gave the green light, so Don - it's up to you.

Probably our awesome Don will be able to do it, sooner or later :-)
 He also agreed to give more thought to the restriction of forcing every 
 swich label to be ended with a control flow transfer statement.

Good :-) Bye, bearophile
Jun 20 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 He also agreed to give more thought to the restriction of forcing every 
 swich label to be ended with a control flow transfer statement.

I hope Walter will express his positive vote about this other little C syntax detail, automatic joining of adjacent strings: http://d.puremagic.com/issues/show_bug.cgi?id=3827 Bye, bearophile
Jun 20 2010
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu Wrote:

 On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

Walter just gave the green light, so Don - it's up to you. He also agreed to give more thought to the restriction of forcing every swich label to be ended with a control flow transfer statement.

You mean every label that is followed by a statement, correct? This is a common idiom that I wouldn't want to change: switch (x) { case 1: case 2: case 3: case 4: doSomething(); break; default: whatever(); }
Jun 20 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:
 You mean every label that is followed by a statement, correct?  This is a
common idiom that I wouldn't want to change:
 
 switch (x) {
 case 1: case 2: case 3: case 4:
     doSomething();
     break;
 default:
     whatever();
 }

I think he means every case. Sometimes a small change, even if seems a little less handy, is useful. Can't you write code like this, that also looks better to me? import std.stdio: writeln; void doSomething() { writeln("doSomething"); } void whatever() { writeln("whatever"); } void main() { int x = 4; switch (x) { case 1, 2, 3, 4: doSomething(); break; default: whatever(); break; } } Bye, bearophile
Jun 20 2010
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
bearophile Wrote:

 Sean Kelly:
 You mean every label that is followed by a statement, correct?  This is a
common idiom that I wouldn't want to change:
 
 switch (x) {
 case 1: case 2: case 3: case 4:
     doSomething();
     break;
 default:
     whatever();
 }

I think he means every case. Sometimes a small change, even if seems a little less handy, is useful. Can't you write code like this, that also looks better to me? import std.stdio: writeln; void doSomething() { writeln("doSomething"); } void whatever() { writeln("whatever"); } void main() { int x = 4; switch (x) { case 1, 2, 3, 4: doSomething(); break; default: whatever(); break; } }

As long as there's a way to enumerate case labels I don't really care what the syntax is. That would be more than fine with me.
Jun 20 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:

 As long as there's a way to enumerate case labels I don't really care what the
syntax is.  That would be more than fine with me.

Good (note that the code I have written is already correct D syntax) :-) Bye, bearophile
Jun 20 2010
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-06-20 19:42:49 -0400, bearophile <bearophileHUGS lycos.com> said:

 I think he means every case. Sometimes a small change, even if seems a 
 little less handy, is useful. Can't you write code like this, that also 
 looks better to me?
 
 import std.stdio: writeln;
 void doSomething() { writeln("doSomething"); }
 void whatever() { writeln("whatever"); }
 void main() {
     int x = 4;
     switch (x) {
         case 1, 2, 3, 4:
             doSomething();
             break;
         default:
             whatever();
             break;
     }
 }

But what about the "case 1: ... case 10:" syntax? switch (x) { case 1: .. case 10: case 22: .. case 32: case 52, 64: doSomething(); break; default: whatever(); break; } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 20 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Michel Fortin:
 But what about the "case 1: ... case 10:" syntax?

You are right, I think we have to make an exception on this then, and consider that range a single entity. (You have just found an example why a conceptually messed up syntax (like that ranged one) always comes to bite us in the butt sooner or later.) Bye, bearophile
Jun 20 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Michel Fortin:
 But what about the "case 1: ... case 10:" syntax?
 
 	switch (x) {
 		case 1: .. case 10:
 		case 22: .. case 32:
 		case 52, 64:
 			doSomething();
 			break;
 		default:
 			whatever();
 			break;
 	}

Sorry, in my first answer I have a bit partially misunderstood your question. You can write that like this, but I think this is not compatible with the current syntax (after commas you can of course add a newline): case 1: .. case 10, case 22: .. case 32, 52, 64: Otherwise you can keep them splitted (this needs no syntax changes): case 1: .. case 10: goto case; case 22: .. case 32: goto case; case 52, 64: One of my original proposals was this, that now can not be used: case 1 ... 10, 22 ... 32, 52, 64: Bye, bearophile
Jun 20 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/20/2010 09:00 PM, bearophile wrote:
 Michel Fortin:
 But what about the "case 1: ... case 10:" syntax?

 	switch (x) {
 		case 1: .. case 10:
 		case 22: .. case 32:
 		case 52, 64:
 			doSomething();
 			break;
 		default:
 			whatever();
 			break;
 	}

Sorry, in my first answer I have a bit partially misunderstood your question. You can write that like this, but I think this is not compatible with the current syntax (after commas you can of course add a newline): case 1: .. case 10, case 22: .. case 32, 52, 64: Otherwise you can keep them splitted (this needs no syntax changes): case 1: .. case 10: goto case; case 22: .. case 32: goto case; case 52, 64: One of my original proposals was this, that now can not be used: case 1 ... 10, 22 ... 32, 52, 64:

The intent is to only require a control flow transfer if there is at least one statement after the label. Andrei
Jun 20 2010
next sibling parent BCS <none anon.com> writes:
Hello Andrei,

 On 06/20/2010 09:00 PM, bearophile wrote:
 
 Michel Fortin:
 
 But what about the "case 1: ... case 10:" syntax?
 
 switch (x) {
 case 1: .. case 10:
 case 22: .. case 32:
 case 52, 64:
 doSomething();
 break;
 default:
 whatever();
 break;
 }

question. You can write that like this, but I think this is not compatible with the current syntax (after commas you can of course add a newline): case 1: .. case 10, case 22: .. case 32, 52, 64: Otherwise you can keep them splitted (this needs no syntax changes): case 1: .. case 10: goto case; case 22: .. case 32: goto case; case 52, 64: One of my original proposals was this, that now can not be used: case 1 ... 10, 22 ... 32, 52, 64:

least one statement after the label.

Anyone who fails to include that special case in there proposal should have there hard drive reformatted, with soap. http://www.youtube.com/watch?v=Ktzt096mlxs -- ... <IXOYE><
Jun 20 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

The intent is to only require a control flow transfer if there is at least one
statement after the label.<

The current switch syntax is already very hairy (even lot of people on this newsgroup are ignorant about some parts of it!) and it contains one or more special cases. So I suggest to avoid adding one more special case. Special cases are bad. Bye, bearophile
Jun 21 2010
next sibling parent Don <nospam nospam.com> writes:
bearophile wrote:
 Andrei:
 
 The intent is to only require a control flow transfer if there is at least one
statement after the label.<

The current switch syntax is already very hairy (even lot of people on this newsgroup are ignorant about some parts of it!) and it contains one or more special cases. So I suggest to avoid adding one more special case. Special cases are bad.

You seem to be doing the best you can to torpedo this proposal by adding an extra requirement to it, which is both painful and useless. Please stop now.
Jun 21 2010
prev sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Jun 21, 10 17:52, bearophile wrote:
 Andrei:

 The intent is to only require a control flow transfer if there is at least one
statement after the label.<

The current switch syntax is already very hairy (even lot of people on this newsgroup are ignorant about some parts of it!) and it contains one or more special cases. So I suggest to avoid adding one more special case. Special cases are bad. Bye, bearophile

That is just C#'s switch syntax. And I don't see how the current switch syntax is "hairy".
Jun 21 2010
parent bearophile <bearophileHUGS lycos.com> writes:
KennyTM~:
 That is just C#'s switch syntax.

Some of the C# designers are people with a long experience in implementing (Pascal-like) programming languages. Convergent evolution is a way to confirm my idea was good, then :-)
And I don't see how the current switch syntax is "hairy".<

Even if you aren't able to see it, it doesn't change the fact that D switch syntax is made by several enhancements (or even fixes, like the one currently discussed, and time ago in bugzilla I have asked for another fix to the switch syntax) over the C switch syntax that is quite unclean and unsafe to start with (see Duff's device for an example of how unclean it is, or the recently introduced "static switch" of D that patches a common bug source). After about three years of using D I am able to forget that "goto case;" is a valid syntax. In another answer Jonathan M Davis says something similar:
I forgot about that one. *Sigh* D has so many cool little features that
sometimes it feels like I'm forgetting at least half of them. Oh well. It's
silly to complain that D has too much cool stuff.<

The recently introduced ranged case syntax can be handy, but it's not a clean thing. So D switches are quite hairy. Somewhere we'll have to write a short list of the differences between D and C switches. Bye, bearophile
Jun 21 2010
prev sibling parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

Walter just gave the green light, so Don - it's up to you.

I patched my DMD. Quite successful. It caught 8 bugs in Phobos, in code written by at least 4 different people. I think everyone gets stung by that B.
Jun 21 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 03:08 PM, Don wrote:
 Andrei Alexandrescu wrote:
 On 06/19/2010 06:58 AM, Don wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 [snip]
 Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

Walter just gave the green light, so Don - it's up to you.

I patched my DMD. Quite successful. It caught 8 bugs in Phobos, in code written by at least 4 different people. I think everyone gets stung by that B.

This is pretty amazing. Can't wait to see the checkin! It might be interesting to see how many bugs are caught by restricting the switch statement. Andrei
Jun 21 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Don:
 I patched my DMD. Quite successful. It caught 8 bugs in Phobos, in code 
 written by at least 4 different people. I think everyone gets stung by 
 that B.

Thank you Don. Bye, bearophile
Jun 21 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:

 Tragic. Can we end this madness?
 Could we give & | ^ the same precedence as ==, making
 (a & mask == b) an error, just as (a < b == c) is rejected?
 That way we could lay this common bug to rest.

You can change the dmd compiler (even D1, if you want) applying this change and create a compiled "experiment version" that people can try (even people that don't compile dmd every day), to see possible side effects of this change, use it to spot bugs in their D code or inside Phobos, etc.
 BTW I think this a great cautionary tale about the dangers of rating 
 backwards compatibility too highly.

Beside that one, there are few other parts of C/D code that I'd like still to turn into syntax errors in D2, like: 1) Implicit string concat (bug 3827, with an incomplete patch): string[] a = ["foo", "bar" "baz"]; 2) switch cases that don't end with goto or break: void main() { int x, y; switch (x) { case 0: y++; default: y--; } } 3) Several usages of C comma operator. And few others that I don't remember now. ---------------- Andrei Alexandrescu:
 A perhaps little known thing is that D doesn't allow this:
 int a, b, c;
 if (a < b < c) { ... }
 although it's compilable code in C.

It's a pity C compatibily forbids to use that syntax in D, because chained comparison operator syntax is handy in Python to tell if a value is in a range:
 1 < 5 < 10



 "hello" < "zeta" < "red"



Bye, bearophile
Jun 18 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
bearophile:
 1 < 5 < 10




It's especially useful when the value in the middle is the result of some function call: if 1 < foo(5) < 10: ... In D you have to use a temporary variable: auto aux = foo(5); if (1 < aux && aux < 10) { ... Bye, bearophile
Jun 18 2010
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
bearophile wrote:

 2) switch cases that don't end with goto or break:
 
 void main() {
     int x, y;
     switch (x) {
         case 0: y++;
         default: y--;
     }
 }

I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements. - Jonathan M Davis
Jun 18 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:
 but requiring that each case end with a break would seriously restrict 
 the usefulness of switch statements.

Time ago there was a long thread about this topic (and in the meantime Walter has added the "static switch" that burns the fat chance to add to D2 a second safer switch that fixes both the common kind of bugs caused by C switch statements and not just the enum-switch bugs avoided by the current static switch!) and I am not sure it's right to restart that discussion again. Anyway, can you show me one example where requiring that each case end with a break OR goto restricts the usefulness of switch statements? Bye, bearophile
Jun 18 2010
parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
bearophile wrote:

 Jonathan M Davis:
 but requiring that each case end with a break would seriously restrict
 the usefulness of switch statements.

Time ago there was a long thread about this topic (and in the meantime Walter has added the "static switch" that burns the fat chance to add to D2 a second safer switch that fixes both the common kind of bugs caused by C switch statements and not just the enum-switch bugs avoided by the current static switch!) and I am not sure it's right to restart that discussion again. Anyway, can you show me one example where requiring that each case end with a break OR goto restricts the usefulness of switch statements? Bye, bearophile

Well, I would pount out that you mentioning it more or less reopens the discussion, but in any case, the simplest answer would be if you have multiple values for the variable that your switching on which should all be using the same kind. Fortunately, D simplifies that by allowing you to put multiple values with a single case. An extension of that is if you have two cases which are almost identical but where one of them needs to do something first before the code that is common between both cases. A more complicated example would be one where you're doing something like Duff's Device: send(to, from, count) register short *to, *from; register count; { register n=(count+7)/8; switch(count%8){ case 0: do{ *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; }while(--n>0); } } Even if you drop the whole issue of the loop interleaving with the case statements in Duff's Device, you could still have a situation where you would have a series of things that should be done with how many of them you do depending on what the value you're switching on and you doing all of the preceding ones for each greater value. e.g. switch(value) { case 0: do something... case 1: do something else... case 2: do a third thing... case 3: do yet more... } If value were 0, you'd need to do everything that is done at each case statement, while if it were 2, you'd only need to do whatever is done for 2 and 3. I grant you that in most cases, you don't need to do that sort of thing and that missing a break is an error, but there are definitely cases where being able to have case statements fall through can be quite handy. If it wouldn't likely break compatability with C/C++, I'd suggest requiring a continue if you wanted to fall through (since that wouldn't require a new keyword), but I think that that would break compatibility in cases where the switch is in a loop, so that's probably a no-go, and I very much doubt that Walter would want to add the keyword fallthrough or something similar. It is an issue, but it's a well-known one, and I don't think that requiring a break is worth the loss of power. If we push for a change, it should probably be in requiring a keyword to indicate that you meant to fall through. That would give you the safety without losing the power. - Jonathan M Davis
Jun 18 2010
next sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Jonathan M Davis wrote:

...
 the simplest answer would be if you have
 multiple values for the variable that your switching on which should all
 be using the same kind.

Yikes, that should be "using the same _code_."
Jun 18 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

Well, I would pount out that you mentioning it more or less reopens the
discussion,<

You are right, but probably Walter will not sue me for reopening an old thread ;-) In the things you are saying you seem to ignore the "goto" I have written two times in my answers :-)
An extension of that is if you have two cases which are almost identical but
where one of them needs to do something first before the code that is common
between both cases.<

You can write this C-style switch: switch (x) { case 0: foo(); case 1: bar(); } As this (this is D syntax that you can already use): void main() { int x, y; switch (x) { case 0: y++; goto case 1; case 1: y++; default: } }
 A more complicated example would be one where you're doing something like
 Duff's Device:
 
 send(to, from, count)
 register short *to, *from;
 register count;
 {
         register n=(count+7)/8;
         switch(count%8){
         case 0: do{     *to = *from++;
         case 7:         *to = *from++;
         case 6:         *to = *from++;
         case 5:         *to = *from++;
         case 4:         *to = *from++;
         case 3:         *to = *from++;
         case 2:         *to = *from++;
         case 1:         *to = *from++;
                 }while(--n>0);
         }
 }

You can use gotos (this is a different function, it copies whole arrays, 'to' too is incremented): import std.stdio: writeln; void arrryCopy(short* to, short* from, int count) { foreach (_; 0 .. count / 8) { *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; } final switch (count % 8) { case 7: *to++ = *from++; goto case 6; case 6: *to++ = *from++; goto case 5; case 5: *to++ = *from++; goto case 4; case 4: *to++ = *from++; goto case 3; case 3: *to++ = *from++; goto case 2; case 2: *to++ = *from++; goto case 1; case 1: *to++ = *from++; break; case 0: break; } } void main() { short[9] a1 = 1; short[a1.length] a2; writeln(a1, " ", a2); arrryCopy(a2.ptr, a1.ptr, a1.length); writeln(a1, " ", a2); } I have used the static switch to avoid the default case. Using gotos like that is a bit less conventient than the C code, but I think it can be acceptable.
 switch(value)
 {
     case 0:
         do something...
     case 1:
         do something else...
     case 2:
         do a third thing...
     case 3:
         do yet more...
 }

You can translate it as: switch(value) { case 0: do something... goto case 1; case 1: do something else... goto case 2; case 2: do a third thing... goto case 3; case 3: do yet more... break; default: ... } Bye, bearophile
Jun 18 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
 As this (this is D syntax that you can already use):
 
 void main() {
     int x, y;
     switch (x) {
         case 0: y++; goto case 1;
         case 1: y++;
         default:
     }
 }

Sorry, I meant something like: void main() { int x, y; switch (x) { case 0: y++; goto case 1; case 1: y++; break; default: break; } } Bye, bearophile
Jun 18 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
bearophile wrote:

 Jonathan M Davis:
 
Well, I would pount out that you mentioning it more or less reopens the
discussion,<

You are right, but probably Walter will not sue me for reopening an old thread ;-) In the things you are saying you seem to ignore the "goto" I have written two times in my answers :-)

I had forgotten about that use of goto. I do find it a bit ugly, but it works and makes it possible to require some sort of flow control statement at the end of a case block, thereby avoiding bugs where you forget a break. I can't say that I'm enamoured at the idea of having to use goto for fallthrough, but I wouldn't be opposed to it. Part of the issue, I suppose, is that not only do I definitely use fallthrough at least some of the time, but I'm totally used to being aware of the issue and being appropriately careful about it. So, I don't see it as all that big a problem. However, it's enough of a problem for some people (and even those who are fully aware of it and pay attention do screw up from time to time) that it could very well merit requiring a goto for fallthrough. - Jonathan M Davis
Jun 18 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jonathan M Davis wrote:
 bearophile wrote:
 
 2) switch cases that don't end with goto or break:

 void main() {
     int x, y;
     switch (x) {
         case 0: y++;
         default: y--;
     }
 }

I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements.

I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual. A while ago it was proposed to require each case block to end with a control flow transfer statement (break, continue, return, throw, or goto case XXX). The latter allows fall through in the rare cases that were needed, requiring just a bit of extra umph from the programmer. Perfect solution. My recollection of the matter is that Walter rejected the proposal claiming that he uses fall through all the time. Don ran some measurements over Walter's own code and proved him copiously wrong. Walter had no retort to that argument, so he veered into a critique of the goto case XXX solution saying it's unmaintainable: when you moving code around you want to keep on falling through but with goto you'd need to update the goto target. However, it can be argued that logically you want to continue processing at some specific logical point, not to blindly fall through to whatever the heck code happens to be there. So ultimately the whole thing fizzled. Apparently the current situation is optimal for programmers who use fall through "all the time", who move code that is fallen into all the time, have weird expectations of code after the move, and never check that jumps are made to the right labels. As an aside, I think it's an interesting psychological phenomenon: I think we often have skewed beliefs about the frequency of our patterns. It often happens that switchers to a new language believe they won't be able to make it through the day without feature X (bitfields, anyone? :o)) yet practical experience soon shows otherwise. Andrei
Jun 18 2010
next sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:

 Jonathan M Davis wrote:
 bearophile wrote:
 
 2) switch cases that don't end with goto or break:

 void main() {
     int x, y;
     switch (x) {
         case 0: y++;
         default: y--;
     }
 }

I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements.

I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual.

Certainly a good principle and one that D holds to for the most part - certainly far better than many other languages.
 
 A while ago it was proposed to require each case block to end with a
 control flow transfer statement (break, continue, return, throw, or goto
 case XXX). The latter allows fall through in the rare cases that were
 needed, requiring just a bit of extra umph from the programmer. Perfect
 solution.
 
 My recollection of the matter is that Walter rejected the proposal
 claiming that he uses fall through all the time. Don ran some
 measurements over Walter's own code and proved him copiously wrong.
 Walter had no retort to that argument, so he veered into a critique of
 the goto case XXX solution saying it's unmaintainable: when you moving
 code around you want to keep on falling through but with goto you'd need
 to update the goto target. However, it can be argued that logically you
 want to continue processing at some specific logical point, not to
 blindly fall through to whatever the heck code happens to be there.
 
 So ultimately the whole thing fizzled. Apparently the current situation
 is optimal for programmers who use fall through "all the time", who move
 code that is fallen into all the time, have weird expectations of code
 after the move, and never check that jumps are made to the right labels.

Requiring goto for fallthrough certainly strikes me as less maintainable (if nothing else because you have to say where you're going - if you could just indicate fallthrough without having to indicate a jump target, it wouldn't really be a problem) but not necessarily unacceptabley so. I use fallthrough often enough that I definitely want to have it, but I'm not rearranging my switch statements so often that having to fix the gotos would be a huge source of errors (though being able to just indicate fallthrough - maybe with just goto with no target, though that could be a problem with the grammar - wouldn't be as big a problem).
 
 As an aside, I think it's an interesting psychological phenomenon: I
 think we often have skewed beliefs about the frequency of our patterns.
 It often happens that switchers to a new language believe they won't be
 able to make it through the day without feature X (bitfields, anyone?
 :o)) yet practical experience soon shows otherwise.
 
 
 Andrei

It definitely can be interesting. Of course, some of the problem is that there are features that you use semi-often but are easily replaceable while there are other features that you don't necessarily use all that often but would be awful not to have - and knowing what you need ahead of time is often hard. I don't use function pointers all that often, but it can be highly frustrating to program in Java when I could really use a function pointer and don't have one. Of course, that opens up the issue of how useable the feature is as implemented vs how useful it would be if it were useable. I don't use the algorithm library much in C++ because declaring functions or functors to pass to it is just too much of a pain. It's too hard to use for it to be worth it usually. However, D makes that sort of thing much easier with lambdas and inner functions and the like, so I use std.algorithm fairly heavily. In any case, the whole issue of what we really use and what we really need, and how that compares to what we think that we really use and need could probably cover quite a few papers if you really started looking into it. Regardless, whether goto is required for fallthrough in a switch statement or not, I definitely want fallthrough. - Jonathan M Davis
Jun 18 2010
parent Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Fri, 18 Jun 2010 20:17:09 -0700, Jonathan M Davis 
<jmdavisProg gmail.com> wrote:
 I, for one, _want_ case statements to be able to fall through. It would
 be horribly painful in many cases if they couldn't. Now, requiring a
 separate statement like fallthrough or somesuch instead of break might
 not be a bad idea, but requiring that each case end with a break would
 seriously restrict the usefulness of switch statements.

I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual.

Certainly a good principle and one that D holds to for the most part - certainly far better than many other languages.

Follow the principle too much, though, and you end up in the Ruby (more specifically, Rails) camp. It's amazing when you don't need to do something unusual, but *man* have I had problems trying to do what I want with Rails. That said, having used C for a significant period of time, I'm well aware of the fall-through semantics and use it from time to time, but I wouldn't be opposed to removing implicit fall-through from the language. Fall-through doesn't strike me as a big issue in and of itself, but dogmatic languages aren't fun to work with either.
Jun 18 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Vladimir Panteleev wrote:

 Well, if "goto case XXX" is unmaintainable, how about some combination of
 existing keywords? For example, "continue switch;".

Ooh. I like that. I don't know how well that would work with the grammar, but it's fairly aesthetically pleasing and definitely more maintainable than having to indicate where you're going to - not to mention it makes it distinct from situations where you really want to go to a case other than the next one (which would be yet another source of bugs and confusion if you had to use "goto case XXX" when falling through). I definitely would be open to "continue switch." It makes sense and should solve the issue fairly well. The only potential issues that I see are how well it would fit into the grammar and convincing Walter. - Jonathan M Davis
Jun 18 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/18/2010 10:08 PM, Vladimir Panteleev wrote:
 On Sat, 19 Jun 2010 05:22:47 +0300, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter had no retort to that argument, so he veered into a critique of
 the goto case XXX solution saying it's unmaintainable: when you moving
 code around you want to keep on falling through but with goto you'd
 need to update the goto target. However, it can be argued that
 logically you want to continue processing at some specific logical
 point, not to blindly fall through to whatever the heck code happens
 to be there.

Well, if "goto case XXX" is unmaintainable, how about some combination of existing keywords? For example, "continue switch;". -- Best regards, Vladimir mailto:vladimir thecybershadow.net

Clever! Andrei
Jun 19 2010
prev sibling next sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Jun 19, 10 07:17, Jonathan M Davis wrote:
 bearophile wrote:

 2) switch cases that don't end with goto or break:

 void main() {
      int x, y;
      switch (x) {
          case 0: y++;
          default: y--;
      }
 }

I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements. - Jonathan M Davis

This "fallthrough" statement already exists. switch (x) { case 0: do_something(); goto case; case 1: do_more_thing(); goto case; case 2: done(); break; default: error(); break; }
Jun 18 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
KennyTM~:
 This "fallthrough" statement already exists.
 
      switch (x) {
         case 0:
           do_something();
           goto case;
         case 1:
           do_more_thing();
           goto case;
         case 2:
           done();
           break;
         default:
           error();
           break;
      }

I didn't know this, this is a hidden D feature. So it's just a matter of D forbidding the cases that miss an explicit return, goto, or break, assert(0), exit(), and similar. As for the multiple returns in a function this needs a bit of care because this is acceptable: switch (x) { case 0: if (y) goto case; else return x; default: break; } Bye, bearophile
Jun 19 2010
parent KennyTM~ <kennytm gmail.com> writes:
On Jun 19, 10 17:56, bearophile wrote:
 KennyTM~:
 This "fallthrough" statement already exists.

       switch (x) {
          case 0:
            do_something();
            goto case;
          case 1:
            do_more_thing();
            goto case;
          case 2:
            done();
            break;
          default:
            error();
            break;
       }

I didn't know this, this is a hidden D feature. So it's just a matter of D forbidding the cases that miss an explicit return, goto, or break, assert(0), exit(), and similar. As for the multiple returns in a function this needs a bit of care because this is acceptable: switch (x) { case 0: if (y) goto case; else return x; default: break; } Bye, bearophile

Actually it's not hidden :) http://www.digitalmars.com/d/1.0/statement.html#GotoStatement http://www.digitalmars.com/d/2.0/statement.html#GotoStatement
Jun 19 2010
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
KennyTM~ wrote:

 On Jun 19, 10 07:17, Jonathan M Davis wrote:
 bearophile wrote:

 2) switch cases that don't end with goto or break:

 void main() {
      int x, y;
      switch (x) {
          case 0: y++;
          default: y--;
      }
 }

I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements. - Jonathan M Davis

This "fallthrough" statement already exists. switch (x) { case 0: do_something(); goto case; case 1: do_more_thing(); goto case; case 2: done(); break; default: error(); break; }

I forgot about that one. *Sigh* D has so many cool little features that sometimes it feels like I'm forgetting at least half of them. Oh well. It's silly to complain that D has too much cool stuff. In any case, that means that it could be made required to have a control statement at the end of a case block without having to specify a specific destination for fallthrough - though I'd prefer "continue switch" over "goto case" since it's more explicit and less error prone (since there's no doubt that you didn't intend to put a destination for the goto if you use "continue switch" instead of a "goto case" without a destination). But we do have enough to make a control statement required without adding anything else to the language. Thanks for pointing out that little detail of goto. - Jonathan M Davis
Jun 21 2010
parent reply Sean Kelly <sean invisibleduck.org> writes:
Jonathan M Davis Wrote:
 
 In any case, that means that it could be made required to have a control 
 statement at the end of a case block without having to specify a specific 
 destination for fallthrough - though I'd prefer "continue switch" over "goto 
 case" since it's more explicit and less error prone (since there's no doubt 
 that you didn't intend to put a destination for the goto if you use 
 "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?
Jun 21 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:
 Having never encountered D before, what would be your interpretation of this
code?

Unfortunately the "continue case;" syntax looks about equally unintuitive to me :-( Bye, bearophile
Jun 21 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 01:27 PM, Sean Kelly wrote:
 Jonathan M Davis Wrote:
 In any case, that means that it could be made required to have a control
 statement at the end of a case block without having to specify a specific
 destination for fallthrough - though I'd prefer "continue switch" over "goto
 case" since it's more explicit and less error prone (since there's no doubt
 that you didn't intend to put a destination for the goto if you use
 "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

Well looks pretty good to me to be honest. Andrei
Jun 21 2010
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 06/21/2010 01:27 PM, Sean Kelly wrote:
 Jonathan M Davis Wrote:
 
 In any case, that means that it could be made required to have a
 control
 statement at the end of a case block without having to specify a
 specific
 destination for fallthrough - though I'd prefer "continue switch"
 over "goto
 case" since it's more explicit and less error prone (since there's
 no doubt
 that you didn't intend to put a destination for the goto if you use
 "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

Well looks pretty good to me to be honest.

So would you say "done!" is printed or not?
Jun 21 2010
next sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 06/21/2010 03:46 PM, Sean Kelly wrote:
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:
 On 06/21/2010 01:27 PM, Sean Kelly wrote:
 Jonathan M Davis Wrote:
 In any case, that means that it could be made required to have a
 control
 statement at the end of a case block without having to specify a
 specific
 destination for fallthrough - though I'd prefer "continue switch"
 over "goto
 case" since it's more explicit and less error prone (since there's
 no doubt
 that you didn't intend to put a destination for the goto if you use
 "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

Well looks pretty good to me to be honest.

So would you say "done!" is printed or not?

I say it isn't because the switch predicate is only evaluated once and if you change it after evaluation it doesn't matter. *Placing bet of 5 pixels* Oh, wait, does 'continue switch' go back up to the top like what continue does in a loop? *quietly withdraws bet*
Jun 21 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 03:46 PM, Sean Kelly wrote:
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:
 On 06/21/2010 01:27 PM, Sean Kelly wrote:
 Jonathan M Davis Wrote:
 In any case, that means that it could be made required to have a
 control
 statement at the end of a case block without having to specify a
 specific
 destination for fallthrough - though I'd prefer "continue switch"
 over "goto
 case" since it's more explicit and less error prone (since there's
 no doubt
 that you didn't intend to put a destination for the goto if you use
 "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

Well looks pretty good to me to be honest.

So would you say "done!" is printed or not?

I'd say "continue switch" does not reevaluate getState() because switch is not a looping statement. So I'd think it simply continues down, so writeln is not printed. But I realize I am biased. Andrei
Jun 21 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 07:40 PM, Adam Ruppe wrote:
 What's the point of a switch without implicit fallthrough? If you take
 that away, it offers nothing that if/elseif doesn't. (Aside from not
 retyping the switch(stuff here), which you can bring into a function
 anyway, so whoop-de-doo. And I guess some performance boosts in
 rearranging the cases, but can't the optimizer do that in if/else
 anyway?)

 int Case(in int value) { return myvar == value; }

 if(Case(10)) {

 } else if (Case(20)) {

 } else  { /* default */ }

 You can even use goto and labels to simulate goto case.


 I'm quite serious here: fallthrough is the defining feature of the
 switch.

Then why are people using switch and next to nobody uses fall through (provably including Walter, who thinks is using fall through "all the time")? Simple: because it's a structure expressing handling of a value against a set of values, whereas cascaded if/else is more general and therefore less structured. The same argument could be made in favor of axing for since we already have while. Andrei
Jun 21 2010
parent Don <nospam nospam.com> writes:
Adam Ruppe wrote:
 On 6/21/10, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 Then why are people using switch and next to nobody uses fall through
 (provably including Walter, who thinks is using fall through "all the
 time")?

Do you have some stats from the phobos and dmd source? I ran a crude text pattern program, and it said about 10% of cases fall through in them combined, but since it is so simple, it is surely inaccurate. (It gave 1% for druntime, and 3% for my own code, then 10% for dmd and phobos both. All numbers are rounded to one significant figure. That 3% is surprising - I know I use fallthrough all the time, but most the cases are two cases right next to each other, one one case falling through to default, which my program didn't count. It only considered a case to fallthrough if there was at least one semicolon between it and the next, and it ignored "default".

Did you consider situations where the last thing before the case is actually a 'goto' ? Walter does that a lot.
 
 If it included "case '(': case ')':", like in std.regex, it would be
 much higher, but if the patch disallows that, they'll be riots in the
 streets, so it isn't going to happen.)
 
 Anywho, if my program is even in the right ballpark, I wouldn't call
 that "next to nobody". 10% is a pretty big amount.
 
 
 
 
 On 6/21/10, Leandro Lucarella <luca llucax.com.ar> wrote:
 Well, while, do..while are also redundant, you can do it with for. And
 you can do for with goto!

Indeed. goto is a kind of comfort construct to me. Even if I never use it, it is reassuring to know it is there if I need it. Anything can be built out of goto!
 And you can still use fall-through with the proposed semantics of
 switch, it's just making it explicit instead of implicit.

I tend to write // fallthrough right now anyway to silence [s]the incompetent dweebs[/s] my valued colleagues who complain about fallthrough being there, so assuming the patch doesn't make me riot in the streets, I know it isn't really that big of a change. But still, I resist all change on principle anyway :)

Jun 21 2010
prev sibling next sibling parent Don <nospam nospam.com> writes:
Steven Schveighoffer wrote:
 On Mon, 21 Jun 2010 20:40:14 -0400, Adam Ruppe 
 <destructionator gmail.com> wrote:
 
 What's the point of a switch without implicit fallthrough?

Maintenance. Using if statements instead of switch, you have to repeat the value to test for each of the cases. If you want to change the value being tested, it's one change. And your workaround using a delegate is not very appealing. I'll also point out that popular languages have a switch statement and don't allow implicit fallthrough, meaning that 100% of switch statements do not have fallthrough. And switch is used quite often in those languages too, so at least some people think it has use besides allowing implcit fallthrough. I think mostly it's because the meaning of it is so easy to understand when reading/writing it. When you see a switch, you know what it is and what it isn't. An if statement has many possibilities and must be read more carefully. -Steve

I believe that the switch statement originated as the equivalent of an asm jump table. You have a list of values, and a list of addresses to jump to. The existence of fallthough seems to be an implementation artifact.
Jun 22 2010
prev sibling parent Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Tue, 22 Jun 2010 09:17:57 -0400, Adam Ruppe 
<destructionator gmail.com> wrote:
 
 What you guys are saying makes enough sense. switch will always be a
 series of labels and jumps in my mind, but I can deal with this.
 
 One note that I think is the main reason people find fallthrough
 confusing: they hit tab once too many times.
 
 switch(a) {
     case 10:
     case 20: // obvious fallthrough, no break directly above it
     break; // obvious break - same indentation as the case, just like
 braces would be
     case 30:
 }
 
 I notice a lot of other people indent the break further than the case,
 which is something I only do if the break is not the last statement
 (which means it is probably indented twice, being inside an if or
 something.)
 
 
 Oh well.

I would argue the exact opposite. I think it's not immediately clear what's associated with each case label in the example given. It's a matter of personal preference, though, in the end. I leave labels (both for switches and goto) at the left-most position of their enclosing block: switch (a) { case 5: case 10: break; default: ; } void main () { goto doSomething; doSomething: writeln("foobar"); } But I know there will probably be lots of people who dislike that as well. :P
Jun 23 2010
prev sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Sean Kelly wrote:

 Jonathan M Davis Wrote:
 
 In any case, that means that it could be made required to have a control
 statement at the end of a case block without having to specify a specific
 destination for fallthrough - though I'd prefer "continue switch" over
 "goto case" since it's more explicit and less error prone (since there's
 no doubt that you didn't intend to put a destination for the goto if you
 use "continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

I hadn't thought of that. That could be a source of confusion. However, since a switch statement isn't a loop, and it's not a construct in any other language AFAIK, the person will look it up. Once you've looked it up, I don't think that it would be particularly hard to remember what it actually does. It's quite clear what's going once you've become familiar with the construct and is quite unambiguous in comparison to "goto case" which could easily be missing the target case rather than being meant for fallthrough. So, perhaps it's not immediately intuitive, but many language constructs are, and I think that it's fairly clear once you've looked it up. Having something like "fallthrough" or "goto next case" would of course be even clearer, but those would require new keywords. I still think that "continue switch" would be clearer than "goto case" as well as less error prone. Personally, I think that the fact that it's less error prone alone makes it a better choice even if it were somewhat less clear. - Jonathan M Davis
Jun 21 2010
next sibling parent reply Don <nospam nospam.com> writes:
Jonathan M Davis wrote:
 Sean Kelly wrote:
 
 Jonathan M Davis Wrote:
 In any case, that means that it could be made required to have a control
 statement at the end of a case block without having to specify a specific
 destination for fallthrough - though I'd prefer "continue switch" over
 "goto case" since it's more explicit and less error prone (since there's
 no doubt that you didn't intend to put a destination for the goto if you
 use "continue switch" instead of a "goto case" without a destination).

Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

I hadn't thought of that. That could be a source of confusion. However, since a switch statement isn't a loop, and it's not a construct in any other language AFAIK, the person will look it up. Once you've looked it up, I don't think that it would be particularly hard to remember what it actually does. It's quite clear what's going once you've become familiar with the construct and is quite unambiguous in comparison to "goto case" which could easily be missing the target case rather than being meant for fallthrough. So, perhaps it's not immediately intuitive, but many language constructs are, and I think that it's fairly clear once you've looked it up. Having something like "fallthrough" or "goto next case" would of course be even clearer, but those would require new keywords. I still think that "continue switch" would be clearer than "goto case" as well as less error prone. Personally, I think that the fact that it's less error prone alone makes it a better choice even if it were somewhat less clear. - Jonathan M Davis

But 'goto case XXX' is an extremely rarely encountered construct, that screams 'Examine this code closely'. So I don't think it needs extra error checking.
Jun 21 2010
next sibling parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Don wrote:
 
 But 'goto case XXX' is an extremely rarely encountered construct, that
 screams 'Examine this code closely'. So I don't think it needs extra
 error checking.

Oh, I don't think that it's a big issue. We have "goto case XXX" and "goto case," so we could use them to enforce flow control statements at the end of case blocks without changing anything other than what the compiler complains about. I definitely think that "continue switch" is less error prone than "goto case," and I'd prefer "continue switch," but "goto case XXX" is indeed rare enough that the frequency of screwing up and using "goto case" instead of "goto case XXX" would be quite small. So, I definitely find "continue switch" to be preferable, but it's not a big deal. - Jonathan M Davis
Jun 21 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 04:15 PM, Don wrote:
 Jonathan M Davis wrote:
 Sean Kelly wrote:

 Jonathan M Davis Wrote:
 In any case, that means that it could be made required to have a
 control
 statement at the end of a case block without having to specify a
 specific
 destination for fallthrough - though I'd prefer "continue switch" over
 "goto case" since it's more explicit and less error prone (since
 there's
 no doubt that you didn't intend to put a destination for the goto if
 you
 use "continue switch" instead of a "goto case" without a destination).

misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

I hadn't thought of that. That could be a source of confusion. However, since a switch statement isn't a loop, and it's not a construct in any other language AFAIK, the person will look it up. Once you've looked it up, I don't think that it would be particularly hard to remember what it actually does. It's quite clear what's going once you've become familiar with the construct and is quite unambiguous in comparison to "goto case" which could easily be missing the target case rather than being meant for fallthrough. So, perhaps it's not immediately intuitive, but many language constructs are, and I think that it's fairly clear once you've looked it up. Having something like "fallthrough" or "goto next case" would of course be even clearer, but those would require new keywords. I still think that "continue switch" would be clearer than "goto case" as well as less error prone. Personally, I think that the fact that it's less error prone alone makes it a better choice even if it were somewhat less clear. - Jonathan M Davis

But 'goto case XXX' is an extremely rarely encountered construct, that screams 'Examine this code closely'. So I don't think it needs extra error checking.

After Sean's example, goto case XXX is my fave for fallthrough. I don't like unlabeled "goto case" to mean fall through, it's one of those "need to look in the manual" features. goto case XXX is generalized fall through. Andrei
Jun 21 2010
parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:
 
 After Sean's example, goto case XXX is my fave for fallthrough. I don't
 like unlabeled "goto case" to mean fall through, it's one of those "need
 to look in the manual" features. goto case XXX is generalized fall
 through.
 
 Andrei

Well, it definitely works, but then you run into the issue of whether you used the right XXX. That's the kind of place that rearranging code is likely to run into bugs whereas "goto case" by itself or "continue switch" would just fall through. It also makes it less obvious when you have errors with "goto case XXX" being intended to jump somewhere other than the next case. If you're using a statement that is explicitly for falling through, then it's clearly differentiated from a statement where you're jumping to a case other than the next one. I can't say that I'm terribly found of "goto case" by itself, but at least it would be less likely to cause bugs when rearranging code and more clearly indicates the intention to fall through. It still isn't as good a statement which can only be used for fallthrough (and therefore couldn't be a "goto case" where you were supposed to put a target but didn't), but I see no advantage in using "goto case XXX" for fallthrough instead of "goto case". "goto case" does seem a bit silly, but I think that it's clearer and less error prone for anyone who understands "goto case." The only issue is the fact that it would be odd for someone who didn't know that you could do that, but there's plenty of that to go around already, and it's not like it would be hard to remember when you see it if you've already looked it up. - Jonathan M Davis
Jun 21 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 06:01 PM, Jonathan M Davis wrote:
 Andrei Alexandrescu wrote:
 After Sean's example, goto case XXX is my fave for fallthrough. I don't
 like unlabeled "goto case" to mean fall through, it's one of those "need
 to look in the manual" features. goto case XXX is generalized fall
 through.

 Andrei

Well, it definitely works, but then you run into the issue of whether you used the right XXX. That's the kind of place that rearranging code is likely to run into bugs whereas "goto case" by itself or "continue switch" would just fall through.

Here's where statistics come forward: - code that uses fall through: rare - code that uses fall through and needs to be rearranged: rare * rare - code that uses fall through, needs to be rearranged, and the rearranger doesn't even look at the statement IMMEDIATELY PRECEDING the moved case label: rare * rare * rare We're looking at three orders of magnitude here. I think it's reasonable to not dedicate too much language design to this case.
 It also makes it less obvious when you have errors with
 "goto case XXX" being intended to jump somewhere other than the next case.

Example that may actually refer to real-world code? Even Duff's device will have a sensible definition, albeit more verbose (which is GOOD): each label action will end with "goto case that_label-1".
 If you're using a statement that is explicitly for falling through, then
 it's clearly differentiated from a statement where you're jumping to a case
 other than the next one.

I have zero empathy with that distinction. On the contrary, I think code should be written in terms of going from one label handler to another, instead of falling into whatever comes next.
 I can't say that I'm terribly found of "goto case"
 by itself, but at least it would be less likely to cause bugs when
 rearranging code and more clearly indicates the intention to fall through.

Zero.Empathy.
 It still isn't as good a statement which can only be used for fallthrough
 (and therefore couldn't be a "goto case" where you were supposed to put a
 target but didn't), but I see no advantage in using "goto case XXX" for
 fallthrough instead of "goto case".

I see no disadvantage, and on the contrary, many disadvantages for the cryptic "goto case". (What if it means go again to the current case?) The problem is, if Walter sees us bickering too much, he'll use that as pretext to veto out any improvement.
 "goto case" does seem a bit silly, but I think that it's clearer

No clarity for me.
 and less
 error prone for anyone who understands "goto case."

I don't see that.
 The only issue is the
 fact that it would be odd for someone who didn't know that you could do
 that, but there's plenty of that to go around already, and it's not like it
 would be hard to remember when you see it if you've already looked it up.

Yeah, but it's not like we want to add such cases without necessity. Andrei
Jun 21 2010
next sibling parent reply Jonathan M Davis <jmdavisProg gmail.com> writes:
Andrei Alexandrescu wrote:

[snip]
 
 
 Andrei

Well, "goto case" and "goto case XXX" both already exist. Both get the job done. So, regardless of which would be better for fallthrough, we can choose to use whichever we want in our code. As it stands, it becomes a matter of preference. I'd love something like "continue switch" or "fallthrough" to indicate explicit fallthrough, but it isn't at all necessary, so it's not worth trying to get Walter to add anything like that. At this point, if Walter makes it so that case blocks must end with a flow control statement of some kind, we're free to use either "goto case" or "goto case XXX" for fallthrough, so unless "goto case" is so bad that we should try to get Walter to get rid of it, I don't think that it's really an issue. We can use whichever one we want and not worry about it. The language is complete enough to require case statements to end with a control statement without losing any flexibility, so I think that we can agree to disagree on which statement is better and/or clearer and try and get Walter to add the compiler error for naked fallthrough. - Jonathan M Davis
Jun 21 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/21/2010 06:56 PM, Jonathan M Davis wrote:
 Andrei Alexandrescu wrote:

 [snip]
 Andrei

Well, "goto case" and "goto case XXX" both already exist. Both get the job done. So, regardless of which would be better for fallthrough, we can choose to use whichever we want in our code. As it stands, it becomes a matter of preference. I'd love something like "continue switch" or "fallthrough" to indicate explicit fallthrough, but it isn't at all necessary, so it's not worth trying to get Walter to add anything like that. At this point, if Walter makes it so that case blocks must end with a flow control statement of some kind, we're free to use either "goto case" or "goto case XXX" for fallthrough, so unless "goto case" is so bad that we should try to get Walter to get rid of it, I don't think that it's really an issue. We can use whichever one we want and not worry about it. The language is complete enough to require case statements to end with a control statement without losing any flexibility, so I think that we can agree to disagree on which statement is better and/or clearer and try and get Walter to add the compiler error for naked fallthrough.

I think that's fair enough. It's really Walter's decision now, and Don's too (because with Walter busy with the 64-bit implementation, it's likely Don is the one to volunteer to implement the thing). Andrei
Jun 21 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 The problem is, if Walter sees us bickering too much, he'll use that as 
 pretext to veto out any improvement.

You are wrong, Walter is an adult able to understand discussions, not a capricious dictator :-) Syntax and other things require discussions, sometimes even longish ones. Bye, bearophile
Jun 21 2010
parent Jonathan M Davis <jmdavisProg gmail.com> writes:
bearophile wrote:

 Andrei Alexandrescu:
 The problem is, if Walter sees us bickering too much, he'll use that as
 pretext to veto out any improvement.

You are wrong, Walter is an adult able to understand discussions, not a capricious dictator :-) Syntax and other things require discussions, sometimes even longish ones. Bye, bearophile

Yes, he's an adult, but if he's not particularly interested in the change to begin with, and the folks who want the change can't agree on what the change should be, he could easily choose to leave things as they are - especially because things work just fine as they are. We'd like to be able to make a particular error harder to make, but it's not exactly a groundbreaking change. Walter could decide to work on more important things rather than worrying about this one. There's nothing childish about that. - Jonathan M Davis
Jun 21 2010
prev sibling parent reply BCS <none anon.com> writes:
Hello Jonathan,

 "goto case" does seem a bit silly, but I think that it's clearer and
 less error prone for anyone who understands "goto case."

Say I have some code with a fall through. If I use the goto case X; version, it allows the cases to be freely reordered. OTOH if I use the other option, it doesn't. I think that the more likely error is for someone to rearrange my code and not notice that a case falls thought (with goto case; this causes a bug) rather than rearrange it and expect it to fall through where it doesn't (with goto case X; this causes a bug). For one thing, if you want it to fall thought, you are already thinking about that issue. -- ... <IXOYE><
Jun 21 2010
parent Jonathan M Davis <jmdavisProg gmail.com> writes:
BCS wrote:

 Hello Jonathan,
 
 "goto case" does seem a bit silly, but I think that it's clearer and
 less error prone for anyone who understands "goto case."

Say I have some code with a fall through. If I use the goto case X; version, it allows the cases to be freely reordered. OTOH if I use the other option, it doesn't. I think that the more likely error is for someone to rearrange my code and not notice that a case falls thought (with goto case; this causes a bug) rather than rearrange it and expect it to fall through where it doesn't (with goto case X; this causes a bug). For one thing, if you want it to fall thought, you are already thinking about that issue.

It seems to be one of those things that definitely differs depending on how you think. At least we have both "goto case" and "goto case XXX," so if it becomes necessary to have a goto of some kind to fall through, we can pick which works best for how we think. If it becomes prevalent enough, it may or may not lead to a set of established ideas on the safest way to do it. At present, you have fallthrough, so most people probably don't use either form of goto. - Jonathan M Davis
Jun 21 2010
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
Jonathan M Davis Wrote:

 Sean Kelly wrote:
 
 It's a small thing, but I think "continue switch" could be misleading. 
 Consider this:
 
 switch (getState()) {
 case X:
     setState(Z);
     continue switch;
 case Y:
     break;
 case Z:
     writeln( "done!" );
 }
 
 Having never encountered D before, what would be your interpretation of
 this code?

I hadn't thought of that. That could be a source of confusion. However, since a switch statement isn't a loop, and it's not a construct in any other language AFAIK, the person will look it up

 Personally, I think that the fact that it's less error prone alone makes it 
 a better choice even if it were somewhat less clear.

I'm inclined to agree. This is just the first thing that popped into my mind when I saw "continue switch" and I figured I'd bring it up.
Jun 21 2010
prev sibling parent reply Jeff Nowakowski <jeff dilacero.org> writes:
On 06/21/2010 05:11 PM, Jonathan M Davis wrote:
 Having something like "fallthrough" or "goto next case" would of
 course be even clearer, but those would require new keywords.

I think "fallthrough" would be a perfect keyword to add here. C programmers will immediately recognize it. Switch/case are already specialized keywords, and fallthrough can complete the set. It's unlikely to conflict with existing source, and this is one case where having a conspicuously long keyword is a good thing. Finally, goto is ugly and continue is strongly associated with looping.
Jun 21 2010
parent reply Don <nospam nospam.com> writes:
Jeff Nowakowski wrote:
 On 06/21/2010 05:11 PM, Jonathan M Davis wrote:
 Having something like "fallthrough" or "goto next case" would of
 course be even clearer, but those would require new keywords.

I think "fallthrough" would be a perfect keyword to add here. C programmers will immediately recognize it. Switch/case are already specialized keywords, and fallthrough can complete the set. It's unlikely to conflict with existing source, and this is one case where having a conspicuously long keyword is a good thing. Finally, goto is ugly and continue is strongly associated with looping.

? It's most commonly used in error handling. But, fallthrough actually is a goto.
Jun 21 2010
parent reply Jeff Nowakowski <jeff dilacero.org> writes:
On 06/22/2010 12:06 AM, Don wrote:
 Finally, goto is ugly and continue is strongly associated with looping.

? It's most commonly used in error handling. But, fallthrough actually is a goto.

Do I really have to argue that goto is mostly deprecated, and has been for decades? Lots of programming constructs are specialized versions of goto. Sure, a well placed goto can still be good in some error handling situations, but it's use should be limited. Anyways, I find it interesting that somebody in another post said they already put //fallthrough comment in their code, which supports that the most obvious and simplest thing to do is make it a keyword. It would also make for a good suggestion in an error message: "fallthrough required".
Jun 22 2010
parent reply Don <nospam nospam.com> writes:
Jeff Nowakowski wrote:
 On 06/22/2010 12:06 AM, Don wrote:
 Finally, goto is ugly and continue is strongly associated with looping.

? It's most commonly used in error handling. But, fallthrough actually is a goto.

Do I really have to argue that goto is mostly deprecated, and has been for decades?

I think you misunderstood. I was arguing that there is no association between 'goto' and loops. People who use goto, use it for error handling, not for looping. I was by no means advocating the use of goto for error handling!
Jun 22 2010
parent Jeff Nowakowski <jeff dilacero.org> writes:
On 06/22/2010 08:39 AM, Don wrote:
 I think you misunderstood. I was arguing that there is no association
 between 'goto' and loops. People who use goto, use it for error
 handling, not for looping. I was by no means advocating the use of goto
 for error handling!

Oh good :) The looping part wasn't about "goto", it was about the alternate proposal of reusing "continue" to mean fallthrough.
Jun 22 2010
prev sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Jonathan M Davis, el 21 de junio a las 17:03 me escribiste:
 bearophile wrote:
 
 Andrei Alexandrescu:
 The problem is, if Walter sees us bickering too much, he'll use that as
 pretext to veto out any improvement.

You are wrong, Walter is an adult able to understand discussions, not a capricious dictator :-) Syntax and other things require discussions, sometimes even longish ones. Bye, bearophile

Yes, he's an adult, but if he's not particularly interested in the change to begin with, and the folks who want the change can't agree on what the change should be, he could easily choose to leave things as they are - especially because things work just fine as they are. We'd like to be able to make a particular error harder to make, but it's not exactly a groundbreaking change. Walter could decide to work on more important things rather than worrying about this one. There's nothing childish about that.

There is *already* a patch by Chad Joan: http://d.puremagic.com/issues/show_bug.cgi?id=3536 It's not exactly the same proposed here, but if Walter gives green light maybe he'll be happy to update it. Just give him some feedback in that bug report when Walter is comfortable with the change. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Si por el chancho fuera, se autocomería con chimichurri Worshestershire!
Jun 21 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Lars T. Kyllingstad, el 22 de junio a las 09:14 me escribiste:
 On Mon, 21 Jun 2010 20:27:32 -0700, Bill Baxter wrote:
 
 On Mon, Jun 21, 2010 at 6:31 PM, Leandro Lucarella <luca llucax.com.ar>
 wrote:
 Bill Baxter, el 21 de junio a las 17:13 me escribiste:
 On Mon, Jun 21, 2010 at 4:24 PM, Leandro Lucarella
 <luca llucax.com.ar> wrote:
 goto next case; is a little more verbose but very clear to me :)

 Maybe just next case; is a shorter alternative...

That would be great if "next" were a D keyword.  But I don't think you're going to get Walter to add a keyword just for this.

Damn! Where did I get next from? I don't know...

I think it's a keyword in Perl maybe? --bb

It is a keyword in BASIC, at least. :) FOR i = 1 TO 100 PRINT i NEXT

I'm sure it's Perl, even when I written Basic (GW and Q) code, I remember it having the same meaning as C's "continue". -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- According to several sources Dr. Harvey Kellogg tried to make a cure for masturbation When he made cornflakes
Jun 22 2010
prev sibling parent Adam Ruppe <destructionator gmail.com> writes:
What you guys are saying makes enough sense. switch will always be a
series of labels and jumps in my mind, but I can deal with this.

One note that I think is the main reason people find fallthrough
confusing: they hit tab once too many times.

switch(a) {
    case 10:
    case 20: // obvious fallthrough, no break directly above it
    break; // obvious break - same indentation as the case, just like
braces would be
    case 30:
}

I notice a lot of other people indent the break further than the case,
which is something I only do if the break is not the last statement
(which means it is probably indented twice, being inside an if or
something.)


Oh well.
Jun 22 2010
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 18 Jun 2010 20:23:45 -0400, Jonathan M Davis  
<jmdavisProg gmail.com> wrote:

 bearophile wrote:

 Jonathan M Davis:
 but requiring that each case end with a break would seriously restrict
 the usefulness of switch statements.

Time ago there was a long thread about this topic (and in the meantime Walter has added the "static switch" that burns the fat chance to add to D2 a second safer switch that fixes both the common kind of bugs caused by C switch statements and not just the enum-switch bugs avoided by the current static switch!) and I am not sure it's right to restart that discussion again. Anyway, can you show me one example where requiring that each case end with a break OR goto restricts the usefulness of switch statements? Bye, bearophile

Well, I would pount out that you mentioning it more or less reopens the discussion, but in any case, the simplest answer would be if you have multiple values for the variable that your switching on which should all be using the same kind. Fortunately, D simplifies that by allowing you to put multiple values with a single case. An extension of that is if you have two cases which are almost identical but where one of them needs to do something first before the code that is common between both cases. A more complicated example would be one where you're doing something like Duff's Device: send(to, from, count) register short *to, *from; register count; { register n=(count+7)/8; switch(count%8){ case 0: do{ *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; }while(--n>0); } } Even if you drop the whole issue of the loop interleaving with the case statements in Duff's Device, you could still have a situation where you would have a series of things that should be done with how many of them you do depending on what the value you're switching on and you doing all of the preceding ones for each greater value. e.g. switch(value) { case 0: do something... case 1: do something else... case 2: do a third thing... case 3: do yet more... } If value were 0, you'd need to do everything that is done at each case statement, while if it were 2, you'd only need to do whatever is done for 2 and 3. I grant you that in most cases, you don't need to do that sort of thing and that missing a break is an error, but there are definitely cases where being able to have case statements fall through can be quite handy. If it wouldn't likely break compatability with C/C++, I'd suggest requiring a continue if you wanted to fall through (since that wouldn't require a new keyword), but I think that that would break compatibility in cases where the switch is in a loop, so that's probably a no-go, and I very much doubt that Walter would want to add the keyword fallthrough or something similar. It is an issue, but it's a well-known one, and I don't think that requiring a break is worth the loss of power. If we push for a change, it should probably be in requiring a keyword to indicate that you meant to fall through. That would give you the safety without losing the power. - Jonathan M Davis

continue is a valid keyword inside a switch statement, so no, you can't use it.
Jun 18 2010
prev sibling next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sat, 19 Jun 2010 05:22:47 +0300, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter had no retort to that argument, so he veered into a critique of  
 the goto case XXX solution saying it's unmaintainable: when you moving  
 code around you want to keep on falling through but with goto you'd need  
 to update the goto target. However, it can be argued that logically you  
 want to continue processing at some specific logical point, not to  
 blindly fall through to whatever the heck code happens to be there.

Well, if "goto case XXX" is unmaintainable, how about some combination of existing keywords? For example, "continue switch;". -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Jun 18 2010
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
Did anyone suggest "continue case" instead of "continue switch"?  That
sounds less ambiguous to me.

--bb

On Mon, Jun 21, 2010 at 4:56 PM, Jonathan M Davis <jmdavisProg gmail.com> wrote:
 Andrei Alexandrescu wrote:

 [snip]
 Andrei

Well, "goto case" and "goto case XXX" both already exist. Both get the job done. So, regardless of which would be better for fallthrough, we can choose to use whichever we want in our code. As it stands, it becomes a matter of preference. I'd love something like "continue switch" or "fallthrough" to indicate explicit fallthrough, but it isn't at all necessary, so it's not worth trying to get Walter to add anything like that. At this point, if Walter makes it so that case blocks must end with a flow control statement of some kind, we're free to use either "goto case" or "goto case XXX" for fallthrough, so unless "goto case" is so bad that we should try to get Walter to get rid of it, I don't think that it's really an issue. We can use whichever one we want and not worry about it. The language is complete enough to require case statements to end with a control statement without losing any flexibility, so I think that we can agree to disagree on which statement is better and/or clearer and try and get Walter to add the compiler error for naked fallthrough. - Jonathan M Davis

Jun 21 2010
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Jun 21, 2010 at 4:24 PM, Leandro Lucarella <luca llucax.com.ar> wrote:
 goto next case; is a little more verbose but very clear to me :)

 Maybe just next case; is a shorter alternative...

That would be great if "next" were a D keyword. But I don't think you're going to get Walter to add a keyword just for this. --bb
Jun 21 2010
prev sibling next sibling parent Adam Ruppe <destructionator gmail.com> writes:
What's the point of a switch without implicit fallthrough? If you take
that away, it offers nothing that if/elseif doesn't. (Aside from not
retyping the switch(stuff here), which you can bring into a function
anyway, so whoop-de-doo. And I guess some performance boosts in
rearranging the cases, but can't the optimizer do that in if/else
anyway?)

int Case(in int value) { return myvar == value; }

if(Case(10)) {

} else if (Case(20)) {

} else  { /* default */ }

You can even use goto and labels to simulate goto case.


I'm quite serious here: fallthrough is the defining feature of the
switch. Taking it away leaves you with nothing that if/elseif can't
already do. Might as well just axe the whole thing.

Oh yeah, the final switch would still be useful, since it offers a
check that if/elseif doesn't, but meh, move it to std.typecons, since
it is mostly for enums anyway.


(I'm not actually for removing the switch. I'm firmly in the status quo camp.)
Jun 21 2010
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Jun 21, 2010 at 6:31 PM, Leandro Lucarella <luca llucax.com.ar> wro=
te:
 Bill Baxter, el 21 de junio a las 17:13 me escribiste:
 On Mon, Jun 21, 2010 at 4:24 PM, Leandro Lucarella <luca llucax.com.ar> =


 goto next case; is a little more verbose but very clear to me :)

 Maybe just next case; is a shorter alternative...

That would be great if "next" were a D keyword. =A0But I don't think you're going to get Walter to add a keyword just for this.

Damn! Where did I get next from? I don't know...

I think it's a keyword in Perl maybe? --bb
Jun 21 2010
prev sibling next sibling parent Adam Ruppe <destructionator gmail.com> writes:
On 6/21/10, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 Then why are people using switch and next to nobody uses fall through
 (provably including Walter, who thinks is using fall through "all the
 time")?

Do you have some stats from the phobos and dmd source? I ran a crude text pattern program, and it said about 10% of cases fall through in them combined, but since it is so simple, it is surely inaccurate. (It gave 1% for druntime, and 3% for my own code, then 10% for dmd and phobos both. All numbers are rounded to one significant figure. That 3% is surprising - I know I use fallthrough all the time, but most the cases are two cases right next to each other, one one case falling through to default, which my program didn't count. It only considered a case to fallthrough if there was at least one semicolon between it and the next, and it ignored "default". If it included "case '(': case ')':", like in std.regex, it would be much higher, but if the patch disallows that, they'll be riots in the streets, so it isn't going to happen.) Anywho, if my program is even in the right ballpark, I wouldn't call that "next to nobody". 10% is a pretty big amount. On 6/21/10, Leandro Lucarella <luca llucax.com.ar> wrote:
 Well, while, do..while are also redundant, you can do it with for. And
 you can do for with goto!

Indeed. goto is a kind of comfort construct to me. Even if I never use it, it is reassuring to know it is there if I need it. Anything can be built out of goto!
 And you can still use fall-through with the proposed semantics of
 switch, it's just making it explicit instead of implicit.

I tend to write // fallthrough right now anyway to silence [s]the incompetent dweebs[/s] my valued colleagues who complain about fallthrough being there, so assuming the patch doesn't make me riot in the streets, I know it isn't really that big of a change. But still, I resist all change on principle anyway :)
Jun 21 2010
prev sibling next sibling parent Adam Ruppe <destructionator gmail.com> writes:
On 6/22/10, Don <nospam nospam.com> wrote:
 Did you consider situations where the last thing before the case is
 actually a 'goto' ? Walter does that a lot.

Yeah, me too. I counted them the same as break (and continue, return, and throw). Here's my source. I know it has some false negatives and some false positives, which is why I rounded so vigorously. ======= import std.string; import std.stdio; void main(string[] args) { int totalSwitchCount, totalFallthroughCount, totalCaseCount, totalCaseFallthroughCount; foreach(arg; args[1..$]) { auto f = File(arg); int fallthroughCount = 0; int switchCount = 0; bool caseAlreadyOpen; bool fallthroughAlready; int caseCount = 0; int caseFallthroughCount; string lastLine; try foreach(line; f.byLine) { // if it says "case .*:", but not goto, we'll call it a switch case if(line.indexOf("case ") != -1 && line.indexOf("goto") == -1 && line.indexOf(":") != -1) { caseCount++; totalCaseCount++; if(caseAlreadyOpen) { // the first one doesn't count if( // If this line, or the last line (with a semicolon) breaks, it isn't fallthrough lastLine.indexOf("break") == -1 && line.indexOf("break") == -1 && // ditto for goto, continue, and return lastLine.indexOf("goto") == -1 && line.indexOf("goto") == -1 && lastLine.indexOf("continue") == -1 && line.indexOf("continue") == -1 && lastLine.indexOf("return") == -1 && line.indexOf("return") == -1 && // and of course, exceptions lastLine.indexOf("throw") == -1 && line.indexOf("throw") == -1 ) { totalCaseFallthroughCount++; caseFallthroughCount++; if(!fallthroughAlready) { fallthroughCount++; totalFallthroughCount++; } fallthroughAlready = true; } } else caseAlreadyOpen = true; } if(line.indexOf("switch") != -1) { totalSwitchCount++; switchCount++; caseAlreadyOpen = false; fallthroughAlready = false; } if(line.indexOf(";") != -1) // only consider lines with semicolons as a crude way to find non-empty cases and ignore whitespace lastLine = line.idup; } catch(Exception e) { } // i don't care writefln("%s: %d/%d (%d/%d cases)", arg, fallthroughCount, switchCount, caseFallthroughCount, caseCount); } writefln("Total switches: %d/%d (%.1f%%)", totalFallthroughCount, totalSwitchCount, cast(float) totalFallthroughCount / totalSwitchCount * 100); writefln(" Total cases: %d/%d (%.1f%%)", totalCaseFallthroughCount, totalCaseCount, cast(float) totalCaseFallthroughCount / totalCaseCount * 100); } ======= I used the try without {} there too, which was mentioned in another thread. I do this often; it never even occurred to me that it wouldn't be allowed. It isn't for if and for, etc, so why would it be for try? I love it.
Jun 21 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Mon, 21 Jun 2010 20:27:32 -0700, Bill Baxter wrote:

 On Mon, Jun 21, 2010 at 6:31 PM, Leandro Lucarella <luca llucax.com.ar>
 wrote:
 Bill Baxter, el 21 de junio a las 17:13 me escribiste:
 On Mon, Jun 21, 2010 at 4:24 PM, Leandro Lucarella
 <luca llucax.com.ar> wrote:
 goto next case; is a little more verbose but very clear to me :)

 Maybe just next case; is a shorter alternative...

That would be great if "next" were a D keyword.  But I don't think you're going to get Walter to add a keyword just for this.

Damn! Where did I get next from? I don't know...

I think it's a keyword in Perl maybe? --bb

It is a keyword in BASIC, at least. :) FOR i = 1 TO 100 PRINT i NEXT -Lars
Jun 22 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 21 Jun 2010 20:40:14 -0400, Adam Ruppe <destructionator gmail.com>  
wrote:

 What's the point of a switch without implicit fallthrough?

Maintenance. Using if statements instead of switch, you have to repeat the value to test for each of the cases. If you want to change the value being tested, it's one change. And your workaround using a delegate is not very appealing. I'll also point out that popular languages have a switch statement and don't allow implicit fallthrough, meaning that 100% of switch statements do not have fallthrough. And switch is used quite often in those languages too, so at least some people think it has use besides allowing implcit fallthrough. I think mostly it's because the meaning of it is so easy to understand when reading/writing it. When you see a switch, you know what it is and what it isn't. An if statement has many possibilities and must be read more carefully. -Steve
Jun 22 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Tue, 22 Jun 2010 02:40:14 +0200, Adam Ruppe <destructionator gmail.com>  
wrote:

 What's the point of a switch without implicit fallthrough? If you take
 that away, it offers nothing that if/elseif doesn't. (Aside from not
 retyping the switch(stuff here), which you can bring into a function
 anyway, so whoop-de-doo. And I guess some performance boosts in
 rearranging the cases, but can't the optimizer do that in if/else
 anyway?)

 int Case(in int value) { return myvar == value; }

 if(Case(10)) {

 } else if (Case(20)) {

 } else  { /* default */ }

 You can even use goto and labels to simulate goto case.

Well, if you like sacrificing clarity for writing more verbose code, feel free. Switch is valuable for its clarity - '} else if (Case(12)) {' is nowhere near as easily parsable as 'case 12'. -- Simen
Jun 22 2010
prev sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Steven Schveighoffer, el 22 de junio a las 07:26 me escribiste:
 On Mon, 21 Jun 2010 20:40:14 -0400, Adam Ruppe
 <destructionator gmail.com> wrote:
 
What's the point of a switch without implicit fallthrough?

Maintenance. Using if statements instead of switch, you have to repeat the value to test for each of the cases. If you want to change the value being tested, it's one change. And your workaround using a delegate is not very appealing.

And it's a bit comfortable when used with expressions that should be evaluated just one: switch (foo()) { case xxx: ... case yyy: ... } vs auto tmp = foo(); if (tmp == xxx) { ... else if (tmp == yyy) { ... }
 I'll also point out that popular languages have a switch statement
 and don't allow implicit fallthrough, meaning that 100% of switch
 statements do not have fallthrough.  And switch is used quite often
 in those languages too, so at least some people think it has use
 besides allowing implcit fallthrough.
 
 I think mostly it's because the meaning of it is so easy to
 understand when reading/writing it.  When you see a switch, you know
 what it is and what it isn't.  An if statement has many
 possibilities and must be read more carefully.

Like for/while vs goto and foreach vs while/for. They are specializations for common uses. It helps both the programmer to write/read more clear code and the compiler to generate more efficient code because they have a more defined semantics and it can make more assumptions. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Creativity is great but plagiarism is faster
Jun 22 2010
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 18 Jun 2010 17:03:24 -0400, Don <nospam nospam.com> wrote:

 In the comments for bug 4077, "Bugs caused by bitwise operator  
 precedence"
 it was asked why C gave & with lower precedence than ==, when it is  
 unintuitive and a frequent source of bugs.

 I was quite shocked to find that the reason is backwards compatibility  
 with the B programming language.

 Denis Ritchie says (http://cm.bell-labs.com/cm/cs/who/dmr/chist.html):
 --------------------
 At the suggestion of Alan Snyder, I introduced the && and || operators  
 to make the mechanism [[short circuit evaluation]] more explicit.

 Their tardy introduction explains an infelicity of C's precedence rules.  
 In B one writes

      if (a==b & c) ...

 to check whether a equals b and c is non-zero; in such a conditional  
 expression it is better that & have lower precedence than ==. In  
 converting from B to C, one wants to replace & by && in such a  
 statement; to make the conversion less painful, we decided to keep the  
 precedence of the & operator the same relative to ==, and merely split  
 the precedence of && slightly from &. Today, it seems that it would have  
 been preferable to move the relative precedences of & and
 ==, and thereby simplify a common C idiom: to test a masked value  
 against another value, one must write

      if ((a&mask) == b) ...

 where the inner parentheses are required but easily forgotten.
 -----------------------------------
 Tragic. Can we end this madness?

 Could we give & | ^ the same precedence as ==, making
 (a & mask == b) an error, just as (a < b == c) is rejected?
 That way we could lay this common bug to rest. I've personally lost days  
 of my life to this one. It's a bug 100% of the time.

 Or is too late to break backwards compatibility with B ?

 BTW I think this a great cautionary tale about the dangers of rating  
 backwards compatibility too highly.

Well, you've got a big vote++ from this a & mask == b bug survivor. I also think your solution is simple and elegant.
Jun 18 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Justin Johansson, el 19 de junio a las 23:24 me escribiste:
 Andrei Alexandrescu wrote:
On 06/19/2010 06:58 AM, Don wrote:
Andrei Alexandrescu wrote:
Don wrote:
[snip]
Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

You may want to make sure Walter approves first. He's the BDFL! Andrei

BDFL = ? Some lame acronym letter tries: B = benevolent D = dictator

For Life Taken from Python. http://en.wikipedia.org/wiki/Benevolent_Dictator_For_Life I don't think Walter is a BDFL, though. He is more a OMD (orchestra-man dictator), as he do everything by himself and nobody could ever do anything else, he doesn't "resolve disputes or competing arguments within the community", he just do what he wants (except from Phobos now, fortunately). -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Hay manos capaces de fabricar herramientas con las que se hacen máquinas para hacer ordenadores que a su vez diseñan máquinas que hacen herramientas para que las use la mano
Jun 19 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Andrei Alexandrescu, el 19 de junio a las 03:15 me escribiste:
 On 06/18/2010 10:08 PM, Vladimir Panteleev wrote:
On Sat, 19 Jun 2010 05:22:47 +0300, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

Walter had no retort to that argument, so he veered into a critique of
the goto case XXX solution saying it's unmaintainable: when you moving
code around you want to keep on falling through but with goto you'd
need to update the goto target. However, it can be argued that
logically you want to continue processing at some specific logical
point, not to blindly fall through to whatever the heck code happens
to be there.

Well, if "goto case XXX" is unmaintainable, how about some combination of existing keywords? For example, "continue switch;". -- Best regards, Vladimir mailto:vladimir thecybershadow.net

Clever!

Search the archives for the multiple fall-through threads. All have been suggested before. http://www.digitalmars.com/d/archives/154.html#N388 -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Y Gloria Carrá, Gloria Estephan, Gloria Gaynor y Gloria Trevi. -- Peperino Pómoro
Jun 19 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Andrei Alexandrescu, el 21 de junio a las 15:31 me escribiste:
 On 06/21/2010 03:08 PM, Don wrote:
Andrei Alexandrescu wrote:
On 06/19/2010 06:58 AM, Don wrote:
Andrei Alexandrescu wrote:
Don wrote:
[snip]
Or is too late to break backwards compatibility with B ?

We can and should do it. It won't impact TDPL adversely.

Excellent! I'll make a patch for it when I have time.

Walter just gave the green light, so Don - it's up to you.

I patched my DMD. Quite successful. It caught 8 bugs in Phobos, in code written by at least 4 different people. I think everyone gets stung by that B.

This is pretty amazing. Can't wait to see the checkin! It might be interesting to see how many bugs are caught by restricting the switch statement.

There is already a patch for that: http://d.puremagic.com/issues/show_bug.cgi?id=3536 Maybe is not perfect (it adds a new flavour of case to allow implicit fall-through), but it's something =). And just to experiment with, it should be good enough, since it makes the default case syntax forbids implicit fall-through, so it's not necessary to change any code to try it (if it still applies to trunk, which probably is not the case anymore). -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Ya ni el cielo me quiere, ya ni la muerte me visita Ya ni el sol me calienta, ya ni el viento me acaricia
Jun 21 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Andrei Alexandrescu, el 21 de junio a las 15:25 me escribiste:
 On 06/21/2010 01:27 PM, Sean Kelly wrote:
Jonathan M Davis Wrote:
In any case, that means that it could be made required to have a control
statement at the end of a case block without having to specify a specific
destination for fallthrough - though I'd prefer "continue switch" over "goto
case" since it's more explicit and less error prone (since there's no doubt
that you didn't intend to put a destination for the goto if you use
"continue switch" instead of a "goto case" without a destination).

It's a small thing, but I think "continue switch" could be misleading. Consider this: switch (getState()) { case X: setState(Z); continue switch; case Y: break; case Z: writeln( "done!" ); } Having never encountered D before, what would be your interpretation of this code?

Well looks pretty good to me to be honest.

goto next case; is a little more verbose but very clear to me :) Maybe just next case; is a shorter alternative... -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- CONDUCTOR BORRACHO CASI PROVOCA UNA TRAGEDIA: BATMAN UNICO TESTIGO -- Crónica TV
Jun 21 2010
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Bill Baxter, el 21 de junio a las 17:13 me escribiste:
 On Mon, Jun 21, 2010 at 4:24 PM, Leandro Lucarella <luca llucax.com.ar> wrote:
 goto next case; is a little more verbose but very clear to me :)

 Maybe just next case; is a shorter alternative...

That would be great if "next" were a D keyword. But I don't think you're going to get Walter to add a keyword just for this.

Damn! Where did I get next from? I don't know... -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- "All mail clients suck. This one just sucks less." -me, circa 1995
Jun 21 2010
prev sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Adam Ruppe, el 21 de junio a las 20:40 me escribiste:
 What's the point of a switch without implicit fallthrough? If you take
 that away, it offers nothing that if/elseif doesn't. (Aside from not
 retyping the switch(stuff here), which you can bring into a function
 anyway, so whoop-de-doo. And I guess some performance boosts in
 rearranging the cases, but can't the optimizer do that in if/else
 anyway?)
 
 int Case(in int value) { return myvar == value; }
 
 if(Case(10)) {
 
 } else if (Case(20)) {
 
 } else  { /* default */ }
 
 You can even use goto and labels to simulate goto case.
 
 
 I'm quite serious here: fallthrough is the defining feature of the
 switch. Taking it away leaves you with nothing that if/elseif can't
 already do. Might as well just axe the whole thing.
 
 Oh yeah, the final switch would still be useful, since it offers a
 check that if/elseif doesn't, but meh, move it to std.typecons, since
 it is mostly for enums anyway.
 
 
 (I'm not actually for removing the switch. I'm firmly in the status quo camp.)

Well, while, do..while are also redundant, you can do it with for. And you can do for with goto! The point is providing a nice syntax for common usage patterns, and switch without fall-through is way more common than switch with fall-through, even when fall-through might been the primary "feature" provided by switch in its early ages. And you can still use fall-through with the proposed semantics of switch, it's just making it explicit instead of implicit. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- TIGRE SE COMIO A EMPLEADO DE CIRCO: DETUVIERON A DUEÑO Y DOMADOR -- Crónica TV
Jun 21 2010