digitalmars.D - No more fall through in case statement?
- davidl (4/4) Jan 03 2008 http://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/programmingCsharp...
- 0ffh (4/6) Jan 03 2008 Looks like a compromise, it still falls through for empty cases. =)
- Janice Caron (26/27) Jan 03 2008 I'm sure you know this already, but: "Warnings are not a defined part
- Dan (2/35) Jan 03 2008 It's creative, and syntactically coherent. I like it. Even if it break...
- Janice Caron (14/15) Jan 03 2008 I don't think it would break any old programs at all (which means,
- Steven Schveighoffer (19/23) Jan 03 2008 I haven't done this in any d programs, but in C++ programs, I used to us...
- Mike (25/35) Jan 03 2008 the
- Dan Lewis (5/36) Jan 03 2008 I tend to agree with Steve. Perhaps using case in the same manner as if...
- Matti Niemenmaa (6/8) Jan 04 2008 case a, b, c:
- 0ffh (15/39) Jan 03 2008 Right-ho! I do, but I was thinking of C#, what the article was about. =)
- Michiel Helvensteijn (6/19) Jan 03 2008 But the cases are labels. You fall through labels. To change this for
- 0ffh (7/11) Jan 03 2008 Well, if it's not labels anymore, the implicit break option couln't
- Mike (6/22) Jan 03 2008 I've posted this exact same idea a long time ago. It's just so obviously...
- Bill Baxter (6/11) Jan 03 2008 I'm no C# guy but that looks like a nice way to fix C's switch. "goto
- bearophile (61/64) Jan 03 2008 I think the C switch is broken in 2 or more ways, so I'd like to see D i...
- bearophile (24/44) Jan 03 2008 Let's try again, 2 keywords less:
- Leonard Dahlmann (11/61) Jan 03 2008 I doubt that 'continue' can be used there - what if we have a caseof in ...
- 0ffh (3/4) Jan 03 2008 Same with 'break' - what if we have a switch in a loop? =)
- Carlos Santander (28/92) Jan 03 2008 default you want to go to the end of the switch).
- S. (17/37) Jan 03 2008 This whole conversation about switch was kind of lost on me, but I have ...
- Bill Baxter (9/30) Jan 03 2008 Good news for you, then. Nothing's going to change!
- bearophile (4/5) Jan 03 2008 If you take a look at my original post, I have suggested to use a "fall"...
- S. (14/21) Jan 07 2008 The same problems you initially mentioned still exist in your proposal. ...
- bearophile (9/12) Jan 07 2008 I agree (D too has a simple way to spot dead code under a return in not-...
- Michel Fortin (16/22) Jan 11 2008 A use case?
- Robert DaSilva (2/26) Jan 11 2008 Yes, but it would be 'A' .. 'Z' not 'A' ... 'Z'.
- Janice Caron (3/4) Jan 12 2008 In D parance, that would mean 'A' to 'Y' inclusive, but excluding 'Z'.
- Daniel Lewis (19/25) Jan 12 2008 Not only;
- Jason House (2/29) Jan 13 2008 That's always bugged me. Seems too easy for coding errors.
- Bruce Adams (26/65) Jan 03 2008 =
- S. (6/56) Jan 07 2008 In other news, it has been discovered that the risk of choking is greatl...
- Bruce Adams (34/100) Jan 07 2008 nts
- S. (12/105) Jan 07 2008 Well one probably not. For one, there isn't a formal definition given f...
- Bill Baxter (14/15) Jan 07 2008 Eliminating the possibility of unintentional fall-through altogether
- James Dennett (6/19) Jan 04 2008 C++ fixed this some time in the last century, making the code
- Bill Baxter (3/22) Jan 04 2008 That's actually in the spec? Cool. I thought it was just a QOI thing.
- Robert DaSilva (3/3) Jan 11 2008 I just noticed this in the specs.
- BC (123/125) Jan 04 2008 i had a go at rolling my own, here it is if anyone's interested:
- Bill Baxter (3/147) Jan 04 2008 Neat, but too many braces. :-(((({(}
- Janice Caron (12/29) Jan 04 2008 A mighty and noble effort - but I can't help but feel that the
-
BC
(5/34)
Jan 05 2008
On Fri, 04 Jan 2008 17:26:54 -0000, Janice Caron
- Janice Caron (9/15) Jan 05 2008 Me? Hell no! I don't write compilers. But Walter may be able to answer
- 0ffh (7/19) Jan 05 2008 FWIW I totally agree with you that there is virtual certainty that some
- Bruce Adams (3/19) Jan 05 2008 SAS C++? them were the days...
- Christopher Wright (2/11) Jan 05 2008 I've heard that javac uses table lookups for switch statements.
- Jason House (10/13) Jan 08 2008 You're right that we're capable of doing any and all kinds of stupid thi...
- Rioshin an'Harthen (7/16) Jan 09 2008 I'd like to see either a "break", "continue", or "return" (or any other
http://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html I think I love the trap no.9 -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Jan 03 2008
davidl wrote:[...] I think I love the trap no.9Looks like a compromise, it still falls through for empty cases. =) To me, a warning on nonempty case fallthrough seems more than enough... regards, frank
Jan 03 2008
On 1/3/08, 0ffh <frank youknow.what.todo.internetz> wrote:To me, a warning on nonempty case fallthrough seems more than enough...I'm sure you know this already, but: "Warnings are not a defined part of the D Programming Language." (http://digitalmars.com/d/warnings.html) Either it's an error, or it's not. Hey - here's an idea. Why not make case statements have a syntax similar to D's attributes. That is, if you use a colon, execution continutes to end of scope (or break), but if you use curly braces, only the stuff within the braces gets executed. (Just like "public", "private", etc.) For example: case 1: /*...*/ /* falls through */ case 2: /*...*/ break; case 3 { /*...*/ } /* does not fall through */ Existing syntax will still work, so that C++ programmers won't get confused. To get no-fall-through behaviour, you'd have to replace the colon with an opening curly brace (and remember the closing brace). Everyone's happy. (Maybe?)
Jan 03 2008
Janice Caron Wrote:On 1/3/08, 0ffh <frank youknow.what.todo.internetz> wrote:It's creative, and syntactically coherent. I like it. Even if it breaks my old programs, this one makes sense. : )To me, a warning on nonempty case fallthrough seems more than enough...I'm sure you know this already, but: "Warnings are not a defined part of the D Programming Language." (http://digitalmars.com/d/warnings.html) Either it's an error, or it's not. Hey - here's an idea. Why not make case statements have a syntax similar to D's attributes. That is, if you use a colon, execution continutes to end of scope (or break), but if you use curly braces, only the stuff within the braces gets executed. (Just like "public", "private", etc.) For example: case 1: /*...*/ /* falls through */ case 2: /*...*/ break; case 3 { /*...*/ } /* does not fall through */ Existing syntax will still work, so that C++ programmers won't get confused. To get no-fall-through behaviour, you'd have to replace the colon with an opening curly brace (and remember the closing brace). Everyone's happy. (Maybe?)
Jan 03 2008
On 1/3/08, Dan <murpsoft hotmail.com> wrote:It's creative, and syntactically coherent. I like it. Even if it breaks my old programs, this one makes sense. : )I don't think it would break any old programs at all (which means, maybe it has a fighting chance of getting accepted?). All old and existing code would behave exactly as before, without change. That's because the new behaviour would only come into effect if you used the new syntax. Specifically: case x: (with a colon) implies the existing C behavior - keep executing code until you reach a break, a continue, or a right-brace. Wheras: case x { /*...*/ } (without a colon, but with a left-brace) would mean to execute only that which was within the braces. This construction will never occur in old code, because in existing switch/case syntax, the colon in mandatory.
Jan 03 2008
"Janice Caron" wroteOn 1/3/08, Dan wrote:I haven't done this in any d programs, but in C++ programs, I used to use braces to create a scope in which to declare a variable. What would happen here: case x: { int y = 2; ... } break; I'm not super excited about there being such a subtle difference with the colon (if you automatically put a colon without thinking about it, then the break statement is required, meaning a very subtle bug), but other than that, I like the idea. Why not make it more obvious?: case (x, y, z) // similar to case x: case y: case z: { } /* else case(a, b, c) ? */ -SteveIt's creative, and syntactically coherent. I like it. Even if it breaks my old programs, this one makes sense. : )I don't think it would break any old programs at all
Jan 03 2008
On Thu, 03 Jan 2008 16:43:52 +0100, Steven Schveighoffer = <schveiguy yahoo.com> wrote:I'm not super excited about there being such a subtle difference with =thecolon (if you automatically put a colon without thinking about it, the=n =the break statement is required, meaning a very subtle bug), but other tha=nthat, I like the idea. Why not make it more obvious?: case (x, y, z) // similar to case x: case y: case z: { } /* else case(a, b, c) ? */ -SteveI want to add two things: (1) When using () after case, the {} should be optional, like in an if: case (1) foo(); case (2, 3) { foo(); bar(); } (2) continue should be used for fall through behavior: case (1) foo(); case (2, 3) { if (x =3D=3D 3) continue 1; bar(); } We could even get rid of "default" and label the default case as "else" = - = saving a keyword :) -- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Jan 03 2008
Steven Schveighoffer Wrote:"Janice Caron" wroteI tend to agree with Steve. Perhaps using case in the same manner as if/for/while/switch and the rest is more congruent to other program structures. I also agree that falling through should be explicit. I use it alot, but safe and more common behavior is to not do so. I also like the comma notation; it would probably terse up the giant lexer switch a bit. Regards, DanOn 1/3/08, Dan wrote:I haven't done this in any d programs, but in C++ programs, I used to use braces to create a scope in which to declare a variable. What would happen here: case x: { int y = 2; ... } break; I'm not super excited about there being such a subtle difference with the colon (if you automatically put a colon without thinking about it, then the break statement is required, meaning a very subtle bug), but other than that, I like the idea. Why not make it more obvious?: case (x, y, z) // similar to case x: case y: case z: { } /* else case(a, b, c) ? */ -SteveIt's creative, and syntactically coherent. I like it. Even if it breaks my old programs, this one makes sense. : )I don't think it would break any old programs at all
Jan 03 2008
Dan Lewis wrote:I also like the comma notation; it would probably terse up the giant lexer switch a bit.case a, b, c: is already valid D. http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Jan 04 2008
Janice Caron wrote:On 1/3/08, 0ffh <frank youknow.what.todo.internetz> wrote:Actually, I think that "no warnings" is a mistake, as is "no inline".To me, a warning on nonempty case fallthrough seems more than enough...I'm sure you know this already, but: "Warnings are not a defined part of the D Programming Language." (http://digitalmars.com/d/warnings.html)[...] For example: case 1: /*...*/ /* falls through */ case 2: /*...*/ break; case 3 { /*...*/ } /* does not fall through */ [...] Everyone's happy. (Maybe?)I like it as it is. If it absolutely has to be changed, why not replace the explicit break with an implicit break and make fall- through explicit? Liek so: case 1: /*...*/ fallthrough; // falls through case 2: /*...*/ // no fallthrough -> implicit break case ... I could live with that as a compromise... regards, frank
Jan 03 2008
I like it as it is. If it absolutely has to be changed, why not replace the explicit break with an implicit break and make fall- through explicit? Liek so: case 1: /*...*/ fallthrough; // falls through case 2: /*...*/ // no fallthrough -> implicit break case ... I could live with that as a compromise...But the cases are labels. You fall through labels. To change this for switches would be inconsistent. Actually, I don't like switch statement syntax at all, really. I don't think they should be labels. They should be { } blocks. -- Michiel
Jan 03 2008
Michiel Helvensteijn wrote:But the cases are labels. You fall through labels. To change this for switches would be inconsistent.You're quite right.Actually, I don't like switch statement syntax at all, really. I don't think they should be labels. They should be { } blocks.Well, if it's not labels anymore, the implicit break option couln't break consistency, could it? Anyways, I don't want to go on arguing for a change I'd rather not see implemented, except as a compromise for those who don't like the implicit fallthrough... =) regards, frank
Jan 03 2008
On Thu, 03 Jan 2008 12:03:08 +0100, Janice Caron <caron800 googlemail.com> wrote:For example: case 1: /*...*/ /* falls through */ case 2: /*...*/ break; case 3 { /*...*/ } /* does not fall through */ Existing syntax will still work, so that C++ programmers won't get confused. To get no-fall-through behaviour, you'd have to replace the colon with an opening curly brace (and remember the closing brace). Everyone's happy. (Maybe?)I've posted this exact same idea a long time ago. It's just so obviously how it should be. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Jan 03 2008
davidl wrote:http://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/program ingCsharp_0801.html I think I love the trap no.9case 5" looks like something straight out of Walter's playbook, too. But it's been discussed many times now and it doesn't seem likely Walter's going to change it in D. --bb
Jan 03 2008
Bill Baxter:I think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago: import std.stdio: writefln; void main(string[] args) { switch (args[1]) { int x = 1; // NOT initialized? case "1": writefln("1! x=", x); break; case "2": writefln("2! x=", x); break; } } More on switch-induced bugs: http://www.soft.com/AppNotes/attcrash.html"goto case 5" looks like something straight out of Walter's playbook, too.<I don't like that goto too much... You usually just want do go down (and by default you want to go to the end of the switch).But it's been discussed many times now and it doesn't seem likely Walter's going to change it in D.<I agree with Walter when he says it's better that if a syntax that looks like C works like C (D goes against this rule few times). So we need a syntax that looks different. Instead of switch{} it may be used caseof{}, plus the "default" statement, plus a new statement like "fall" (or something similar) that tells the compiler just to not break, so it's just the opposite of C :-) As example, this is a part of the std.string.capwords function: switch (s[i]) { case ' ': case '\t': case '\f': case '\r': case '\n': case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; } With that syntax it becomes: caseof (s[i]) { case ' ': fall; case '\t': fall; case '\f': fall; case '\r': fall; case '\n': fall; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } } D already follows such "inversion rule" regerding C in some cases, like here: int a = void; In a safe(r) language the default syntax/behavior *must* be the safer one, expecially when this has no/little costs in terms of speed/memory. Bye, bearophile
Jan 03 2008
bearophile:caseof (s[i]) { case ' ': fall; case '\t': fall; case '\f': fall; case '\r': fall; case '\n': fall; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } }Let's try again, 2 keywords less: caseof (s[i]) { case ' ': continue; case '\t': continue; case '\f': continue; case '\r': continue; case '\n': continue; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } else: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } } :-) Bye, bearophile
Jan 03 2008
bearophile Wrote:bearophile:I doubt that 'continue' can be used there - what if we have a caseof in a loop? foreach(x; y) { caseof(s[i]) { case '': continue; // fallthrough or continue the loop? } } One could workaround this by giving the loop a label and using it with 'continue', but still, this might be confusing for beginners.caseof (s[i]) { case ' ': fall; case '\t': fall; case '\f': fall; case '\r': fall; case '\n': fall; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } }Let's try again, 2 keywords less: caseof (s[i]) { case ' ': continue; case '\t': continue; case '\f': continue; case '\r': continue; case '\n': continue; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } else: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } } :-) Bye, bearophile
Jan 03 2008
Leonard Dahlmann wrote:I doubt that 'continue' can be used there - what if we have a caseof in a loop?Same with 'break' - what if we have a switch in a loop? =) regards, frank
Jan 03 2008
bearophile escribi:Bill Baxter:improve it. This is some code I have shown time ago:I think the C switch is broken in 2 or more ways, so I'd like to see Dimport std.stdio: writefln; void main(string[] args) { switch (args[1]) { int x = 1; // NOT initialized? case "1": writefln("1! x=", x); break; case "2": writefln("2! x=", x); break; } } More on switch-induced bugs: http://www.soft.com/AppNotes/attcrash.htmldefault you want to go to the end of the switch)."goto case 5" looks like something straight out of Walter's playbook, too.<I don't like that goto too much... You usually just want do go down (and bygoing to change it in D.<But it's been discussed many times now and it doesn't seem likely Walter'sI agree with Walter when he says it's better that if a syntax that looks likeC works like C (D goes against this rule few times). So we need a syntax that looks different. Instead of switch{} it may be used caseof{}, plus the "default" statement, plus a new statement like "fall" (or something similar) that tells the compiler just to not break, so it's just the opposite of C :-)As example, this is a part of the std.string.capwords function: switch (s[i]) { case ' ': case '\t': case '\f': case '\r': case '\n': case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; } With that syntax it becomes: caseof (s[i]) { case ' ': fall; case '\t': fall; case '\f': fall; case '\r': fall; case '\n': fall; case '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } }How about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; }D already follows such "inversion rule" regerding C in some cases, like here: int a = void; In a safe(r) language the default syntax/behavior *must* be the safer one,expecially when this has no/little costs in terms of speed/memory.Bye, bearophile-- Carlos Santander Bernal
Jan 03 2008
Carlos Santander Wrote:How about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; }This whole conversation about switch was kind of lost on me, but I have to contribute this. I, at various times, have written code that depends on case statements falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.
Jan 03 2008
S. wrote:This whole conversation about switch was kind of lost on me,Don't worry, none of it will ever happen in D, anyway.but I have to contribute this. I, at various times, have written code that depends on case statements falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.Good news for you, then. Nothing's going to change! But man I wish it would, for 2.0 that is. I've been hit at least half-a-dozen times in the past year by missing break statements in my D code. And I have a C++ background! So it's not about familiarity. It bites me when I'm coding C++ just as frequently. It's simply a C/C++ mis-feature that D failed to correct. --bb
Jan 03 2008
S. Wrote:I, at various times, have written code that depends on case statements falling through, while not being identical!If you take a look at my original post, I have suggested to use a "fall" or "continue" statement when you want to go down, and nothing if you want the default of going at the end of the switch... Bye, bearophile
Jan 03 2008
bearophile Wrote:S. Wrote:The same problems you initially mentioned still exist in your proposal. You just moved them around: caseof(Foo) { case 'foo': writeflin("bar"); fall; x = 3; case 'bar': writefln("OMGWTF X != 3"); } Whatever complicated syntax you invent there will be unreachable code. The compiler should produce ERRORS on any unreachable code. The error you linked to is not switch-induced, but stupidity induced. However, I will say this: D is starting to become so complex that it is becoming difficult to understand the entire specification. Once it is no longer feasible to have the spec memorized then it becomes easy to make very silly mistakes. -S.I, at various times, have written code that depends on case statements falling through, while not being identical!If you take a look at my original post, I have suggested to use a "fall" or "continue" statement when you want to go down, and nothing if you want the default of going at the end of the switch... Bye, bearophile
Jan 07 2008
S:The compiler should produce ERRORS on any unreachable code.<I agree (D too has a simple way to spot dead code under a return in not-release mode). Sometimes Pascal syntax is better than the C one, the switch is one of them, I like the Pascal version better. In the Python community people collect use cases, do a simple frequency count of them, and then usually look for a simple solution able to cover most of them. So we can collect some use cases of the switch. I presume most use cases are covered by a Pascal-like syntax. The other situations are probably covered by putting commas between alternative cases. What other use cases do you people have?The error you linked to is not switch-induced, but stupidity induced.<Then the language (and language designers) must be twice intelligent to avoid errors done by "stupid" humans. Technology must adapt itself to the limits of the human brain, otherwise it's far more stupid than the humans. In this situation I think such adaptation doesn't require a more complex syntax or the usage or more CPU or more memory. A change has the disadvantage that it makes D syntax looking a bit less like C, and this may be a disadvantage.However, I will say this: D is starting to become so complex that it is becoming difficult to understand the entire specification. Once it is no longer feasible to have the spec memorized then it becomes easy to make very silly mistakes.<I too like simpler languages better, that's why I like Python and D (D is simpler than C++ still) :-) D has many parts, so it's more complex than a language with less parts, but usually each D part has few interactions with all the other parts, so the actual complexity isn't too much high :-) Bye, bearophile
Jan 07 2008
On 2008-01-07 20:48:54 -0500, bearophile <bearophileHUGS lycos.com> said:In the Python community people collect use cases, do a simple frequency count of them, and then usually look for a simple solution able to cover most of them. So we can collect some use cases of the switch. I presume most use cases are covered by a Pascal-like syntax. The other situations are probably covered by putting commas between alternative cases. What other use cases do you people have?A use case? I quite fancy GCC's extension which allows you to put ranges in case statements, for instance: switch (myChar) { case 'a'...'z': case 'A'...'Z': case '0'...'9': // do something. } I think D should have it too. (Also, since we're at it, it's covered by Pascal.) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 11 2008
Michel Fortin wrote:On 2008-01-07 20:48:54 -0500, bearophile <bearophileHUGS lycos.com> said:Yes, but it would be 'A' .. 'Z' not 'A' ... 'Z'.In the Python community people collect use cases, do a simple frequency count of them, and then usually look for a simple solution able to cover most of them. So we can collect some use cases of the switch. I presume most use cases are covered by a Pascal-like syntax. The other situations are probably covered by putting commas between alternative cases. What other use cases do you people have?A use case? I quite fancy GCC's extension which allows you to put ranges in case statements, for instance: switch (myChar) { case 'a'...'z': case 'A'...'Z': case '0'...'9': // do something. } I think D should have it too. (Also, since we're at it, it's covered by Pascal.)
Jan 11 2008
On 1/12/08, Robert DaSilva <sp.unit.262+digitalmars gmail.com> wrote:Yes, but it would be 'A' .. 'Z' not 'A' ... 'Z'.In D parance, that would mean 'A' to 'Y' inclusive, but excluding 'Z'. (The three dot form could be used to mean "inclusive" though)
Jan 12 2008
Janice Caron Wrote:On 1/12/08, Robert DaSilva <sp.unit.262+digitalmars gmail.com> wrote:Not only; it would violate the 0..length meaning, and he also failed to recognize the syntax we've been pushing for to distinguish the new switch from the old. The new one looks like this: switch(x) { case(y) { } case (z) { } case (a) { } } Why? 1) It's more consistent with other structured D statements. 2) It differentiates it from the old way in our minds 3) It allows us to support both ways for a transition period. 4) The {} is syntactically associated with only affecting what's inside, while : is used to mean "everything after here" which is semantically correct. Regards, DanYes, but it would be 'A' .. 'Z' not 'A' ... 'Z'.In D parance, that would mean 'A' to 'Y' inclusive, but excluding 'Z'. (The three dot form could be used to mean "inclusive" though)
Jan 12 2008
Robert DaSilva wrote:Michel Fortin wrote:That's always bugged me. Seems too easy for coding errors.On 2008-01-07 20:48:54 -0500, bearophile <bearophileHUGS lycos.com> said:Yes, but it would be 'A' .. 'Z' not 'A' ... 'Z'.In the Python community people collect use cases, do a simple frequency count of them, and then usually look for a simple solution able to cover most of them. So we can collect some use cases of the switch. I presume most use cases are covered by a Pascal-like syntax. The other situations are probably covered by putting commas between alternative cases. What other use cases do you people have?A use case? I quite fancy GCC's extension which allows you to put ranges in case statements, for instance: switch (myChar) { case 'a'...'z': case 'A'...'Z': case '0'...'9': // do something. } I think D should have it too. (Also, since we're at it, it's covered by Pascal.)
Jan 13 2008
On Fri, 04 Jan 2008 00:15:25 -0000, S. <S s.com> wrote:Carlos Santander Wrote:e =How about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~=3D capitalize(s[istart .. i]); inword =3D false; } break; default: if (!inword) { if (r.length) r ~=3D ' '; istart =3D i; inword =3D true; } break; }This whole conversation about switch was kind of lost on me, but I hav=to contribute this. I, at various times, have written code that depends on case statements==falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.This whole conversation boggles me. cases should *never* fall through it= s = dangerous. Assuming polymorphism isn't the answer, which can often eliminate the = switch altogether its much cleaner, safer and better encapsulated in general to use a = function call to replace fall through. E.g. : handleBar() { //Do bar stuff } switch(foo) { case 'bob': // do bob stuff handleBar(); case 'bar': handleBar(); case 'baz': // do baz stuff } The switch can always compile to a simple look-up table that way.
Jan 03 2008
Bruce Adams Wrote:On Fri, 04 Jan 2008 00:15:25 -0000, S. <S s.com> wrote:In other news, it has been discovered that the risk of choking is greatly increased by eating anything that is not pureed. As a result, lawmakers have outlawed solid food. Programming requires a brain. You should go read DailyWTF for awhile. It is possible to do the most ridiculous things no matter how carefully the language is crafted. We should just stay away from hand-holding and focus on making things easier. I agree with measures that make debugging easier when dealing with naming and hijacking. However, a simple step-through will reveal a case falling through when it shouldn't. The aforementioned issues are not as easily caught. -S.Carlos Santander Wrote:This whole conversation boggles me. cases should *never* fall through its dangerous.How about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; }This whole conversation about switch was kind of lost on me, but I have to contribute this. I, at various times, have written code that depends on case statements falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.
Jan 07 2008
On Mon, 07 Jan 2008 22:51:31 -0000, S. <S s.com> wrote:Bruce Adams Wrote:=On Fri, 04 Jan 2008 00:15:25 -0000, S. <S s.com> wrote:Carlos Santander Wrote:How about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~=3D capitalize(s[istart .. i]); inword =3D false; } break; default: if (!inword) { if (r.length) r ~=3D ' '; istart =3D i; inword =3D true; } break; }This whole conversation about switch was kind of lost on me, but I =ntshaveto contribute this. I, at various times, have written code that depends on case stateme==falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.This whole conversation boggles me. cases should *never* fall through=its dangerous.In other news, it has been discovered that the risk of choking is =greatly increased by eating anything that is not pureed. As a result,==lawmakers have outlawed solid food.Is that an example of Ignoratio elenchi? = (http://en.wikipedia.org/wiki/Ignoratio_elenchi) Lawmakers never actually outlawed goto but you don't see it used very = often. That's because putting glass in your food is not a good idea.Programming requires a brain.Working in a team requires respecting other people's Brains and level of= = development. Fall through unnecessarily complicates things without adding much if = indeed any power. I'd rather use my brain on the important things.You should go read DailyWTF for awhile. It is possible to do the most==ridiculous things no matter how carefully the language is crafted. We==should just stay away from hand-holding and focus on making things =easier.Its a matter of perspective. Is it easier to debug or easier to read or = = easier to write safe code?I agree with measures that make debugging easier when dealing with =naming and hijacking. However, a simple step-through will reveal a ca=se =falling through when it shouldn't. The aforementioned issues are not =as =easily caught.True but its easier still if you don't need to step through at all. Its = = easy enough to find the source and targets of a goto with a find in your code. Okay its= = nowhere near in the same league as goto but the point's still valid.-S.B. -- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Jan 07 2008
Bruce Adams Wrote:On Mon, 07 Jan 2008 22:51:31 -0000, S. <S s.com> wrote:Well one probably not. For one, there isn't a formal definition given for that term on your cited page. Secondly, my point is that most things that are generic enough to be useful, are inherently dangerous if misused. Consider most kitchen utensils. The ones that are "safe" only do one thing, and if you want a "safe" kitchen then you need hundreds of these gadgets. goto, and break, are defined in such general terms that they are useful over a wide range of constructs. If you want to make things "safe" you need to pollute your "kitchen" with gadgets. I would like to see the specification stay simple enough that know what exactly each "tool" does in a general sense and then apply it in a specific way. Now sometimes, if something is used enough, then it makes sense to have a special tool for it. (Like having a coffee pot instead of just boiling grounds and straining them out later.) This is why I like D instead of just straight up C.Bruce Adams Wrote:Is that an example of Ignoratio elenchi? (http://en.wikipedia.org/wiki/Ignoratio_elenchi) Lawmakers never actually outlawed goto but you don't see it used very often. That's because putting glass in your food is not a good idea.On Fri, 04 Jan 2008 00:15:25 -0000, S. <S s.com> wrote:In other news, it has been discovered that the risk of choking is greatly increased by eating anything that is not pureed. As a result, lawmakers have outlawed solid food.Carlos Santander Wrote:haveHow about using existing D syntax? switch (s[i]) { case ' ', '\t', '\f', '\r', '\n', '\v': if (inword) { r ~= capitalize(s[istart .. i]); inword = false; } break; default: if (!inword) { if (r.length) r ~= ' '; istart = i; inword = true; } break; }This whole conversation about switch was kind of lost on me, but Ito contribute this. I, at various times, have written code that depends on case statements falling through, while not being identical! For example: switch(foo) { case 'bob': //Do bob stuff //Fall through and doo bar stuff too. case 'bar': //Do bar stuff and exit break; case 'baz': //Do some baz stuff break; } Whatever is changed shouldn't break this.This whole conversation boggles me. cases should *never* fall through its dangerous.And calling into another function in order to duplicate functionality requires introduce a new scope.... If the specification is easily understood then there isn't much problem here...Programming requires a brain.Working in a team requires respecting other people's Brains and level of development. Fall through unnecessarily complicates things without adding much if indeed any power. I'd rather use my brain on the important things.It should be easier to write safe code, and easier to debug and easier to read. Sometimes though, the compiler should just warn you when you're using a construct incorrectly. For example, a return statement can cause unreachable code. Should we get rid of the return statement in favor of 15 different keywords to do similar (but specific) things, or make it an error when it produces unreachable code? I think my take on how I run my kitchen is applicable to D.You should go read DailyWTF for awhile. It is possible to do the most ridiculous things no matter how carefully the language is crafted. We should just stay away from hand-holding and focus on making things easier.Its a matter of perspective. Is it easier to debug or easier to read or easier to write safe code?By aforementioned issues I meant hijacking and protection levels. Which are basically the same reason we require our variables to be defined instead of just implying them when they're used. Is the trade off of having to declare your variables worth not having to figure out what is going on when you mistype a variable name? Yes, most certainly. I don't think switch, goto, break, and the like are anything like that. -S.I agree with measures that make debugging easier when dealing with naming and hijacking. However, a simple step-through will reveal a case falling through when it shouldn't. The aforementioned issues are not as easily caught.True but its easier still if you don't need to step through at all. Its easy enough to find the source and targets of a goto with a find in your code. Okay its nowhere near in the same league as goto but the point's still valid.
Jan 07 2008
S. wrote:However, a simple step-through will reveal a case falling through when it shouldn't.Eliminating the possibility of unintentional fall-through altogether will eliminate the need for even your "simple step-through". And simple step through may not be so simple when the program is hundreds of thousands of lines long. Mistaken fall-through in some switch in some function in some module can change a state, and that state can later trigger another different change of state and so on, until finally somewhere your program crashes because of an incorrect state a dozen causal steps away from the original problem. So "simple step through" may mean "simply" stepping through thousands of lines of code to try to figure out where things first went wrong. It can be very non-trivial. Implicit switch fall-through is evil. --bb
Jan 07 2008
bearophile wrote:Bill Baxter:C++ fixed this some time in the last century, making the code above ill-formed (diagnostic required) as it skips the initialization of x. (It's still UB in C99 so far as I know.) -- JamesI think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago: import std.stdio: writefln; void main(string[] args) { switch (args[1]) { int x = 1; // NOT initialized? case "1": writefln("1! x=", x); break; case "2": writefln("2! x=", x); break; } }
Jan 04 2008
James Dennett wrote:bearophile wrote:That's actually in the spec? Cool. I thought it was just a QOI thing. --bbBill Baxter:C++ fixed this some time in the last century, making the code above ill-formed (diagnostic required) as it skips the initialization of x. (It's still UB in C99 so far as I know.)I think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago: import std.stdio: writefln; void main(string[] args) { switch (args[1]) { int x = 1; // NOT initialized? case "1": writefln("1! x=", x); break; case "2": writefln("2! x=", x); break; } }
Jan 04 2008
I just noticed this in the specs. "The third form, goto case;, transfers to the next CaseStatement of the innermost enclosing SwitchStatement."
Jan 11 2008
On Thu, 03 Jan 2008 10:30:09 -0000, davidl <davidl 126.com> wrote:http://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/programmingCsha=rp_0801.htmlI think I love the trap no.9i had a go at rolling my own, here it is if anyone's interested: //public domain import std.stdio; import std.variant; import std.traits; struct SwitchFrame { Variant val; bool active; bool _break; static SwitchFrame opCall(Variant val, bool active, bool _break) { SwitchFrame result; result.val =3D val; result.active =3D active; result._break =3D _break; return result; } } SwitchFrame[] switchStack; void _continue() //execute next case after this one { switchStack[$ - 1].active =3D true; switchStack[$ - 1]._break =3D false; } void _rematch() //execute the next case that matches { switchStack[$ - 1].active =3D false; switchStack[$ - 1]._break =3D false; } void _break() //don't execute any more cases { switchStack[$ - 1].active =3D false; switchStack[$ - 1]._break =3D true; } struct _range(T) { T min; T max; } _range!(T) range(T)(T min, T max) { _range!(T) result; result.min =3D min; result.max =3D max; return result; } struct rangedg(T) { T min; T max; bool func(T val) { return min <=3D val && val <=3D max; } } void myswitch(T, U)(T switchVal, U block) { Variant v =3D switchVal; switchStack ~=3D SwitchFrame(v, false, false); block(); switchStack.length =3D switchStack.length - 1; } void mycase(T...)(T args) { SwitchFrame* frame =3D &switchStack[$ - 1]; if (frame._break) return; if (!frame.active) { foreach (i, arg; args[0 .. $-1]) { if (typeid(T[i]) =3D=3D frame.val.type && arg =3D=3D = frame.val.get!(T[i])) goto success; static if (is (typeof(*arg) U =3D=3D function)) { //writefln("function"); if (arg(frame.val.get!(U))) goto success; } static if (is (T[i] U =3D=3D delegate)) { //writefln("delegate"); if (arg(frame.val.get!(ParameterTypeTuple!(U)))) goto succe= ss; } static if (is (T[i] U =3D=3D _range!(V), V)) { V switchVal1 =3D frame.val.get!(V); if (arg.min <=3D switchVal1 && switchVal1 <=3D arg.max) got= o = success; } } } else { success: _break();// <- change this to change the default action args[$-1](); } } bool always(int a) { return true; } void main() { myswitch(24, { mycase(10, 11, 12, { writefln("10, 11, 12"); = _continue; }); mycase(24, { writefln("24" ); = _rematch; }); mycase(range(3, 25), { writefln("range" ); = _rematch; }); mycase((int a) { return a > 40; }, { writefln(">40" ); = _rematch; }); mycase(&always, { writefln("always" ); = _rematch; }); }); _range!(int) ra =3D {2,3}; }
Jan 04 2008
BC wrote:On Thu, 03 Jan 2008 10:30:09 -0000, davidl <davidl 126.com> wrote:Neat, but too many braces. :-(((({(} --bbhttp://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/program ingCsharp_0801.html I think I love the trap no.9i had a go at rolling my own, here it is if anyone's interested: //public domain import std.stdio; import std.variant; import std.traits; struct SwitchFrame { Variant val; bool active; bool _break; static SwitchFrame opCall(Variant val, bool active, bool _break) { SwitchFrame result; result.val = val; result.active = active; result._break = _break; return result; } } SwitchFrame[] switchStack; void _continue() //execute next case after this one { switchStack[$ - 1].active = true; switchStack[$ - 1]._break = false; } void _rematch() //execute the next case that matches { switchStack[$ - 1].active = false; switchStack[$ - 1]._break = false; } void _break() //don't execute any more cases { switchStack[$ - 1].active = false; switchStack[$ - 1]._break = true; } struct _range(T) { T min; T max; } _range!(T) range(T)(T min, T max) { _range!(T) result; result.min = min; result.max = max; return result; } struct rangedg(T) { T min; T max; bool func(T val) { return min <= val && val <= max; } } void myswitch(T, U)(T switchVal, U block) { Variant v = switchVal; switchStack ~= SwitchFrame(v, false, false); block(); switchStack.length = switchStack.length - 1; } void mycase(T...)(T args) { SwitchFrame* frame = &switchStack[$ - 1]; if (frame._break) return; if (!frame.active) { foreach (i, arg; args[0 .. $-1]) { if (typeid(T[i]) == frame.val.type && arg == frame.val.get!(T[i])) goto success; static if (is (typeof(*arg) U == function)) { //writefln("function"); if (arg(frame.val.get!(U))) goto success; } static if (is (T[i] U == delegate)) { //writefln("delegate"); if (arg(frame.val.get!(ParameterTypeTuple!(U)))) goto success; } static if (is (T[i] U == _range!(V), V)) { V switchVal1 = frame.val.get!(V); if (arg.min <= switchVal1 && switchVal1 <= arg.max) goto success; } } } else { success: _break();// <- change this to change the default action args[$-1](); } } bool always(int a) { return true; } void main() { myswitch(24, { mycase(10, 11, 12, { writefln("10, 11, 12"); _continue; }); mycase(24, { writefln("24" ); _rematch; }); mycase(range(3, 25), { writefln("range" ); _rematch; }); mycase((int a) { return a > 40; }, { writefln(">40" ); _rematch; }); mycase(&always, { writefln("always" ); _rematch; }); }); _range!(int) ra = {2,3}; }
Jan 04 2008
On 1/4/08, BC <notmi_emayl_adreznot hotmail.com.remove.not> wrote:void main() { myswitch(24, { mycase(10, 11, 12, { writefln("10, 11, 12"); _continue; }); mycase(24, { writefln("24" ); _rematch; }); mycase(range(3, 25), { writefln("range" ); _rematch; }); mycase((int a) { return a > 40; }, { writefln(">40" ); _rematch; }); mycase(&always, { writefln("always" ); _rematch; }); }); _range!(int) ra = {2,3}; }A mighty and noble effort - but I can't help but feel that the following is more readable: if (x==10 || x==11 || x==12) writefln("10,11,12"); if (x==24) writefln(24); if (x>=3 && x<=25) writefln("range"); writefln("always"); The way I see it, the advantage of "switch/case" over "if" is that the compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all when "if" is perfectly expressive already?
Jan 04 2008
On Fri, 04 Jan 2008 17:26:54 -0000, Janice Caron <caron800 googlemail.co= m> = wrote:On 1/4/08, BC <notmi_emayl_adreznot hotmail.com.remove.not> wrote:Good point.void main() { myswitch(24, { mycase(10, 11, 12, { writefln("10, 11, 12"); _continue; }); mycase(24, { writefln("24" ); _rematch; }); mycase(range(3, 25), { writefln("range" ); _rematch; }); mycase((int a) { return a > 40; }, { writefln(">40" ); _rematch; }); mycase(&always, { writefln("always" ); _rematch; }); }); _range!(int) ra =3D {2,3}; }A mighty and noble effort - but I can't help but feel that the following is more readable: if (x=3D=3D10 || x=3D=3D11 || x=3D=3D12) writefln("10,11,12"); if (x=3D=3D24) writefln(24); if (x>=3D3 && x<=3D25) writefln("range"); writefln("always");The way I see it, the advantage of "switch/case" over "if" is that the=compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all=when "if" is perfectly expressive already?Do you know if the compilers actually do this?
Jan 05 2008
On 1/5/08, BC <notmi_emayl_adreznot hotmail.com.remove.not> wrote:Me? Hell no! I don't write compilers. But Walter may be able to answer that question for D. I do know the answer for at least one ancient compiler of old. I know that back in the days of AmigaDOS, the Amiga compiler used a choice of two strategies. It would create a simple O(1) lookup table if all the values were contiguous, or nearly contiguous, or an O(log(N)) binary search otherwise. But that was then and this is now and things are bound to be different.The way I see it, the advantage of "switch/case" over "if" is that the compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all when "if" is perfectly expressive already?Do you know if the compilers actually do this?
Jan 05 2008
Janice Caron wrote:On 1/5/08, BC <notmi_emayl_adreznot hotmail.com.remove.not> wrote:FWIW I totally agree with you that there is virtual certainty that some kind of optimisation (jump table, binary search tree, etc.) is actually used in each of DMD and GDC and more or less any optimising compiler. Whatever the target machine is, those are bound to be faster than a linear chain of if-else-ifs (except for extreme cases). regards, frankMe? Hell no! I don't write compilers. [...] I do know the answer for at least one ancient compiler of old. [...] But that was then and this is now and things are bound to be different.The way I see it, the advantage of "switch/case" over "if" is that the compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all when "if" is perfectly expressive already?Do you know if the compilers actually do this?
Jan 05 2008
On Sat, 05 Jan 2008 11:50:33 -0000, Janice Caron <caron800 googlemail.com> wrote:On 1/5/08, BC <notmi_emayl_adreznot hotmail.com.remove.not> wrote:SAS C++? them were the days...Me? Hell no! I don't write compilers. But Walter may be able to answer that question for D. I do know the answer for at least one ancient compiler of old. I know that back in the days of AmigaDOS, the Amiga compiler used a choice of two strategies. It would create a simple O(1) lookup table if all the values were contiguous, or nearly contiguous, or an O(log(N)) binary search otherwise. But that was then and this is now and things are bound to be different.The way I see it, the advantage of "switch/case" over "if" is that the compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all when "if" is perfectly expressive already?Do you know if the compilers actually do this?
Jan 05 2008
BC wrote:On Fri, 04 Jan 2008 17:26:54 -0000, Janice Caron <caron800 googlemail.com> wrote:I've heard that javac uses table lookups for switch statements.The way I see it, the advantage of "switch/case" over "if" is that the compiler might be able to find cool ways to optimize the code (e.g binary search, sparse array lookup, table lookup, whatever). If the compiler can't do that, well then, what's the point of using it at all when "if" is perfectly expressive already?Do you know if the compilers actually do this?
Jan 05 2008
S. Wrote:Programming requires a brain. You should go read DailyWTF for awhile. It is possible to do the most ridiculous things no matter how carefully the language is crafted. We should just stay away from hand-holding and focus on making things easier.You're right that we're capable of doing any and all kinds of stupid things. I'm guilty of missing semicolons, break statements, and all kinds of other stuff. Bugs pop up everywhere. The easier they are for the compiler to spot and the simpler it is for a human to spot, the better. Debugging is not just the job of the programmer who wrote code 5 minutes ago, but also the maintainer 6 months down the road. I also like this quote from the pragmatic programmer: "It's not about if you'll remember, it's about when you'll forget" I consider discussions on making switch statements safer a valid and important discussion... One of my attractions to D is that it's willing to change stuff we hold near and dear in order to find a better way of doing things. My personal take on all this switch stuff is: * Silently falling-through is dangerous (common switch error when coding, easy to miss in code review) * Silently not falling-through is dangerous (to C coders, etc) * A single case with commas is great, but won't be used by all * {} syntax may be a reasonable compromise * Explicitly requiring "break", "fall", or "assert(0)" at the end of a case may be the best solution.
Jan 08 2008
"Jason House" <jason.james.house gmail.com> kirjoitti viestiss news:fm05pk$2v7k$1 digitalmars.com...My personal take on all this switch stuff is: * Silently falling-through is dangerous (common switch error when coding, easy to miss in code review) * Silently not falling-through is dangerous (to C coders, etc) * A single case with commas is great, but won't be used by all * {} syntax may be a reasonable compromise * Explicitly requiring "break", "fall", or "assert(0)" at the end of a case may be the best solution.I'd like to see either a "break", "continue", or "return" (or any other means of exiting a case, like "goto") at the end of a case statement required, but I'd settle for the compiler to at least produce a warning in the case one of these are missing. "continue" at the end of the case statement would mean fall-through behavior, all others are as is.
Jan 09 2008