Re: Feature request: extending comma operator's functionality
On 05/10/12 18:58, H. S. Teoh wrote: On Fri, Oct 05, 2012 at 05:23:40PM +0200, Don Clugston wrote: [...] My feeling is that do{}while() is a fairly useless concept, and this is part of the reason. In my experience genuine do-while loops are extremely rare, and it only takes a slight change to the loop to force a different structure to be used. Conditional loops which don't follow the while(){...} pattern normally follow the loop-and-a-half pattern, also known as begin-while-repeat (I think that's the name Knuth used). I'll call it 'super do': super do { foo(); while(cond); bar(); } which in D is better modelled by: for (;;) { foo(); if (!cond) break; bar(); } This isn't "super do", it's just "loop", the way nature intended. ;-) I've always been an advocate of this construct: loop { // initial part of loop body } while(cond) { // exit point // trailing part of loop body } Looks OK, except that the scopes look wrong. I would hope than a variable declared in the initial part of the body is also visible in the trailing part. The {} don't work properly. Regardless of the syntax, I think it is _the_ fundamental loop construct, and I've always found it odd that most languages don't include it. I first found encountered it in Forth, and have missed it ever since. To some extent, D (and C/C++)'s for-loops exhibit a similar structure: for (X; Y; Z) {} The trailing part of the loop body corresponds with Z; the condition corresponds with Y. Yes. C got 'for' loops right. To avoid the introduction of a new keyword, we may fuse the do-loop and the while-loop together: do { ... } while (cond) { ... } The current do-loop is simply a special case of this construct where the second {...} is replaced with a ;, and the while-loop is a special case of this construct where the initial part of the loop is elided. I argue that this generalized construct is much more useful than the do-loop or while-loop individually, plus it doesn't break any existing code. I agree that it's more useful. But that code was legal until a couple of releases ago, because a trailing ; was not required on do-while loops. do { xxx; } while(cond) { yyy; } means: do { xxx; } while(cond); yyy; Even without that, it puts a huge significance on that semicolon. So I don't think that works. How about: do { ... do while (cond); ... } ? This is technically already legal too, although 'do while(cond);' is currently either a no-op, or an infinite loop.
Re: Feature request: extending comma operator's functionality
On 10/05/2012 03:35 PM, monarch_dodra wrote: On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote: On Friday, October 05, 2012 02:08:14 bearophile wrote: [SNIP] Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Yeah. That comes from C/C++ (and is the same in Java and C#, I believe). I don't know why it works that way. It's definitely annoying. [SNIP] - Jonathan M Davis Because it's the only way to guarantee that x exits when you reach the end of the loop. s/only/simplest/ do { if(true) continue; //Yawn... skip. const x = ... ; } while (predicate(x)); //What's x? Basic goto limitations. Unlike goto though, inserting a "continue" should never create a compile error, so the compiler *has* to guarantee that the if condition references nothing inside its own block. It is annoying, but nothing that can't be fixed with a scope bloc.
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 13:47:00 UTC, monarch_dodra wrote: On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote: On Friday, October 05, 2012 02:08:14 bearophile wrote: [SNIP] Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Yeah. That comes from C/C++ (and is the same in Java and C#, I believe). I don't know why it works that way. It's definitely annoying. [SNIP] - Jonathan M Davis Because it's the only way to guarantee that x exits when you reach the end of the loop. do { if(true) continue; //Yawn... skip. const x = ... ; } while (predicate(x)); //What's x? Basic goto limitations. Unlike goto though, inserting a "continue" should never create a compile error, so the compiler *has* to guarantee that the if condition references nothing inside its own block. It is annoying, but nothing that can't be fixed with a scope bloc. There is a simple way around this... which addresses both concerns raised... 1. Semantics of old code is unchanged. 2. no issue with 'continue' do(const x = ...) { } while(predicate(x));
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 00:39:40 UTC, timotheecour wrote: Is the plan to deprecate comma operator for chaining expressions? I would love to see more syntactic sugar to support tuples, and comma operator would be the best fit for that purpose. eg: import std.typecons; auto fun(){ return tuple(1,"abc"); //1) ideally, we should be able to write: //return (1,"abc"); //with same semantics (and no need to import std.typecons) } //at the call site: currently: auto t=fun(); auto a=t[0]; auto b=t[1]; //2) ideally, we should be able to write: auto (a,b,c)=fun(); //3) or even: (a,b,c)=fun(); Will it be difficult to implement 2)? (by far the most important of 1,2,3) Is 1) and 3) a good idea? Surely the ideal is what you're written but also allowing the omission of parens where it's unambiguous? Just to keep this idea in people's minds: return 1, "abc"; That would seem like the ideal to me as would: double, string fun(double, double n) { return n[0] * n[1], "abc"; } Should these uses require parens like this? (double, string) fun((double, double) n) { return (n[0] * n[1], "abc"); } As discussed before the parens are unavoidable for assignment given the need to avoid breaking vast quantities of code.
Re: Feature request: extending comma operator's functionality
On Fri, Oct 05, 2012 at 05:23:40PM +0200, Don Clugston wrote: [...] > My feeling is that do{}while() is a fairly useless concept, and > this is part of the reason. > In my experience genuine do-while loops are extremely rare, and it > only takes a slight change to the loop to force a different > structure to be used. > Conditional loops which don't follow the while(){...} pattern > normally follow the loop-and-a-half pattern, also known as > begin-while-repeat (I think that's the name Knuth used). I'll call > it 'super do': > > super do { >foo(); >while(cond); >bar(); > } > > which in D is better modelled by: > > for (;;) > { >foo(); >if (!cond) break; >bar(); > } This isn't "super do", it's just "loop", the way nature intended. ;-) I've always been an advocate of this construct: loop { // initial part of loop body } while(cond) { // exit point // trailing part of loop body } To some extent, D (and C/C++)'s for-loops exhibit a similar structure: for (X; Y; Z) {} The trailing part of the loop body corresponds with Z; the condition corresponds with Y. To avoid the introduction of a new keyword, we may fuse the do-loop and the while-loop together: do { ... } while (cond) { ... } The current do-loop is simply a special case of this construct where the second {...} is replaced with a ;, and the while-loop is a special case of this construct where the initial part of the loop is elided. I argue that this generalized construct is much more useful than the do-loop or while-loop individually, plus it doesn't break any existing code. T -- Без труда не выловишь и рыбку из пруда.
Re: Feature request: extending comma operator's functionality
Because it's the only way to guarantee that x exits when you reach the end of the loop. do { if(true) continue; //Yawn... skip. const x = ... ; } while (predicate(x)); //What's x? But the compiler could tell that there is a 'continue' before x was declared, and issue an error when it is used in while(...)
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 15:35:31 UTC, Don Clugston wrote: My feeling is that do{}while() is a fairly useless concept... [SNIP] The most frequent use I have for do while is to hack it to construct break-able blocks actually ^^ : // do { if(!condition1) break; if(!condition2) break; if(!condition3) break; if(!condition4) break; //DO SOMETHING }while(false); // It is a nice way to avoid the dreaded "if(if(if(if(if(if(" triangle. Related: http://d.puremagic.com/issues/show_bug.cgi?id=8622
Re: Feature request: extending comma operator's functionality
On 05/10/12 15:35, monarch_dodra wrote: On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote: On Friday, October 05, 2012 02:08:14 bearophile wrote: [SNIP] Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Yeah. That comes from C/C++ (and is the same in Java and C#, I believe). I don't know why it works that way. It's definitely annoying. [SNIP] - Jonathan M Davis Because it's the only way to guarantee that x exits when you reach the end of the loop. do { if(true) continue; //Yawn... skip. const x = ... ; } while (predicate(x)); //What's x? Basic goto limitations. Unlike goto though, inserting a "continue" should never create a compile error, so the compiler *has* to guarantee that the if condition references nothing inside its own block. It is annoying, but nothing that can't be fixed with a scope bloc. My feeling is that do{}while() is a fairly useless concept, and this is part of the reason. In my experience genuine do-while loops are extremely rare, and it only takes a slight change to the loop to force a different structure to be used. Conditional loops which don't follow the while(){...} pattern normally follow the loop-and-a-half pattern, also known as begin-while-repeat (I think that's the name Knuth used). I'll call it 'super do': super do { foo(); while(cond); bar(); } which in D is better modelled by: for (;;) { foo(); if (!cond) break; bar(); } rather than by a do-while loop. But it's a bit ugly, and doesn't enforce a single break. IMHO it's a shame we've gone with the fairly useless do-while, rather than cleaning up the syntax for loop-and-a-half. I don't think the proposed changes bring us much closer to a useful language construct.
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote: On Friday, October 05, 2012 02:08:14 bearophile wrote: [SNIP] Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Yeah. That comes from C/C++ (and is the same in Java and C#, I believe). I don't know why it works that way. It's definitely annoying. [SNIP] - Jonathan M Davis Because it's the only way to guarantee that x exits when you reach the end of the loop. do { if(true) continue; //Yawn... skip. const x = ... ; } while (predicate(x)); //What's x? Basic goto limitations. Unlike goto though, inserting a "continue" should never create a compile error, so the compiler *has* to guarantee that the if condition references nothing inside its own block. It is annoying, but nothing that can't be fixed with a scope bloc.
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 07:26:43 UTC, Tove wrote: Don't forget the with statement, it's not "just" for switches! In many cases it's actually even better than the proposed changes _and_ it works today! import std.stdio; struct d_is_beautiful { int a=1; int b=2; } void main() { with(d_is_beautiful()) if(a==1) writeln("ok"); else writeln("ko:", a); with(d_is_beautiful()) do { ++a; writeln("iter"); } while(a!=b); } This was news to me. It seems you can also use a tuple for that. That's a pretty decent workaround: import std.typecons; //... with (Tuple!(int, "a")(getInt())) if (a > 9) { //... } else with (Tuple!(char, "b")(getChar())) if (b == 'D') { //... } On Friday, 5 October 2012 at 07:28:29 UTC, Timon Gehr wrote: But if there are else-if clauses, then you end up polluting your namespace, and notice how the syntax of your workaround deteriorates exponentially: ... Check your math. Correction: "the syntax deteriorates only linearly".
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 07:26:43 UTC, Tove wrote: Don't forget the with statement, it's not "just" for switches! In many cases it's actually even better than the proposed changes _and_ it works today! I've asked recently to have declaration inside the with statement too (same as if has now)... I don't remember why exactly now but it definitely seemed useful at the time.
Re: Feature request: extending comma operator's functionality
On 10/04/2012 11:56 PM, Tommi wrote: On Thursday, 4 October 2012 at 21:32:34 UTC, Jonathan M Davis wrote: If you want to restrict the scope of a variable, you can simply use another set of braces to create a new scope. It might be more verbose than desirable, but it works just fine. e.g. { int n = getInt(); if(n > 10) { ... } } But if there are else-if clauses, then you end up polluting your namespace, and notice how the syntax of your workaround deteriorates exponentially: ... Check your math.
Re: Feature request: extending comma operator's functionality
On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote: On Friday, October 05, 2012 02:08:14 bearophile wrote: Tommi: > Maybe we forget about commas then, and extend if-clauses so > that you can properly define variables at the beginning of > it. > Separated by semicolons. Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Don't forget the with statement, it's not "just" for switches! In many cases it's actually even better than the proposed changes _and_ it works today! import std.stdio; struct d_is_beautiful { int a=1; int b=2; } void main() { with(d_is_beautiful()) if(a==1) writeln("ok"); else writeln("ko:", a); with(d_is_beautiful()) do { ++a; writeln("iter"); } while(a!=b); }
Re: Feature request: extending comma operator's functionality
On Friday, October 05, 2012 02:33:45 timotheecour wrote: > Is the plan to deprecate comma operator for chaining expressions? That's all the comma operator does. If it's not chaining expressions, it's not the comma operator (e.g. variables declarations do _not_ use the comma operator even though they can use commas). There is a proposal to remove the comma operator, altering for loops so that they explicitly support using commas like they currently do but otherwise completely removing the comma operator: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP19 > I would love to see more syntactic sugar to support tuples, and > comma operator would be the best fit for that purpose. That's one of the main reasons for the proposal, but nothing has been decided yet. The discussion is here: http://forum.dlang.org/thread/k3ns2a$1ndc$1...@digitalmars.com - Jonathan M Davis
Re: Feature request: extending comma operator's functionality
Is the plan to deprecate comma operator for chaining expressions? I would love to see more syntactic sugar to support tuples, and comma operator would be the best fit for that purpose. eg: import std.typecons; auto fun(){ return tuple(1,"abc"); //1) ideally, we should be able to write: //return (1,"abc"); //with same semantics (and no need to import std.typecons) } //at the call site: currently: auto t=fun(); auto a=t[0]; auto b=t[1]; //2) ideally, we should be able to write: auto (a,b,c)=fun(); //3) or even: (a,b,c)=fun(); Will it be difficult to implement 2)? (by far the most important of 1,2,3) Is 1) and 3) a good idea?
Re: Feature request: extending comma operator's functionality
On Friday, October 05, 2012 02:08:14 bearophile wrote: > Tommi: > > Maybe we forget about commas then, and extend if-clauses so > > that you can properly define variables at the beginning of it. > > Separated by semicolons. > > Regarding definition of variables in D language constructs, there > is one situation where sometimes I find D not handy. This code > can't work: > > do { > const x = ...; > } while (predicate(x)); > > > You need to use: > > T x; > do { > x = ...; > } while (predicate(x)); Yeah. That comes from C/C++ (and is the same in Java and C#, I believe). I don't know why it works that way. It's definitely annoying. Of course, changing it at this point would change the semantics in a potentially code-breaking manner in that if the condition relies on any variables local to the loop having been destroyed, then its behavior will change. That's probably an insanely uncommon situation though - enough so that I'd be all for changing the semantics to have the scope exited _after_ the test is done (assuming that there's not a solid technical reason to keep it as-is). But I have no idea how possible it is to talk Walter into that sort of change. - Jonathan M Davis
Re: Feature request: extending comma operator's functionality
Tommi: Maybe we forget about commas then, and extend if-clauses so that you can properly define variables at the beginning of it. Separated by semicolons. Regarding definition of variables in D language constructs, there is one situation where sometimes I find D not handy. This code can't work: do { const x = ...; } while (predicate(x)); You need to use: T x; do { x = ...; } while (predicate(x)); Bye, bearophile
Re: Feature request: extending comma operator's functionality
On Friday, October 05, 2012 00:36:22 Adam D. Ruppe wrote: > On Thursday, 4 October 2012 at 22:28:24 UTC, David Nadlinger > > wrote: > > how often have you really encountered big syntactic headaches > > because of not having something like this available? > > I do somewhat regularly. The if(auto x = y()) { use x } is pretty > convenient but being limited only to the bool check is kinda weak. Yeah. It would definitely be useful to be able to do like you do with a for loop with an if, but in that case, I'd probably suggest just making it look like it looks like with for. if(auto x = y(); x != 42) {} That would be really cool, but I expect that it would be hard to talk Walter into it. - Jonathan M Davis
Re: Feature request: extending comma operator's functionality
Maybe we forget about commas then, and extend if-clauses so that you can properly define variables at the beginning of it. Separated by semicolons. string name; if (string street = nextStreet(); int number = nextNumber(); auto person = new Person(name); person.livesAt(number, street)) { // use street, number, and person }
Re: Feature request: extending comma operator's functionality
On Thursday, October 04, 2012 23:56:15 Tommi wrote: > > As it stands, there's a good chance that the comma operator is > > actually going to be _removed_ from the language (aside from > > specific use cases such as inside for loops). So, I don't think > > that there's much chance of it being expanded at all. > > I don't see a problem there. I mean, if the comma operator is > kept in specific cases like inside for loop, why not keep (and > expand it's use) it in this specific case of if-clause. You will have a hard sell with _anything_ involving commas other than tuples. Most people consider anything like the comma operator to be evil (or at least very undesirable). - Jonathan M Davis
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 23:16:53 UTC, Tommi wrote: Didn't see that coming. But I think it might be a bug, because assignment expression has precedence over sequencing expression, that is, expressions separated by commas. Although that's not an assignment expression, but a variable definition. I think the following should be a bug then (currently): if (int val = 123, true) { //... } Because the following is a bug: int val = 123, true; // Error: no identifier for declarator int // Error: semicolon expected, not 'true'
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 22:36:47 UTC, Tommi wrote: But I'm not suggesting any kind of change in syntax. This syntax in D currently works (as long as expr2 is convertible to bool): if (Type var = expr1, expr2) { //... } What I'm suggesting is, I think, quite reasonable: make it so that 'var' is visible to 'expr2'. Uh... I was actually wrong. What that syntax really does is this: if (Type var = cast(Type)expr2) { //... } Didn't see that coming. But I think it might be a bug, because assignment expression has precedence over sequencing expression, that is, expressions separated by commas.
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 22:28:24 UTC, David Nadlinger wrote: how often have you really encountered big syntactic headaches because of not having something like this available? I do somewhat regularly. The if(auto x = y()) { use x } is pretty convenient but being limited only to the bool check is kinda weak.
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 22:28:24 UTC, David Nadlinger wrote: Yes, a language designed could make that choice. But not, it certainly won't be considered for D unless it can be shown that the change solves a real problem with the current syntax. But I'm not suggesting any kind of change in syntax. This syntax in D currently works (as long as expr2 is convertible to bool): if (Type var = expr1, expr2) { //... } What I'm suggesting is, I think, quite reasonable: make it so that 'var' is visible to 'expr2'.
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 21:17:51 UTC, Tommi wrote: Could you change it so that expressions, that are separated by commas and inside an if-clause, would have visibility to the variable defined in the first expression? Yes, a language designed could make that choice. But not, it certainly won't be considered for D unless it can be shown that the change solves a real problem with the current syntax. And how often have you really encountered big syntactic headaches because of not having something like this available? David
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 21:32:34 UTC, Jonathan M Davis wrote: If you want to restrict the scope of a variable, you can simply use another set of braces to create a new scope. It might be more verbose than desirable, but it works just fine. e.g. { int n = getInt(); if(n > 10) { ... } } But if there are else-if clauses, then you end up polluting your namespace, and notice how the syntax of your workaround deteriorates exponentially: The extended if-clause syntax: -- if (byte n = fun1(), n > 10) { //... } else if (int n = fun2(), n > 100) { //... } else if (ulong n = fun3(), n > 1000) { //... } The workaround syntax: -- { byte n1 = fun1(); if (n1 > 10) { //... } else { int n2 = fun2(); if (n2 > 100) { //... } else { ulong n3 = fun3(); if (n3 > 1000) { //... } } } } As it stands, there's a good chance that the comma operator is actually going to be _removed_ from the language (aside from specific use cases such as inside for loops). So, I don't think that there's much chance of it being expanded at all. I don't see a problem there. I mean, if the comma operator is kept in specific cases like inside for loop, why not keep (and expand it's use) it in this specific case of if-clause.
Re: Feature request: extending comma operator's functionality
On Thursday, October 04, 2012 23:11:58 Tommi wrote: > Could you change it so that expressions, that are separated by > commas and inside an if-clause, would have visibility to the > variable defined in the first expression? Easier to show than to > explain: > > int getInt() > { > return 11; > } > > void main() > { > if (int n = getInt(), n > 10) // undefined identifier n > { > //... > } > > if (int n = getInt(), ++n, n > 10) // undefined identifier n > { > //... > } > > if (int n = getInt(), getInt() > 10) // OK > { > //... > } > } > > That would make it possible to define variables in the smallest > possible scope, and not pollute the namespace of the enclosing > scope. If you want to restrict the scope of a variable, you can simply use another set of braces to create a new scope. It might be more verbose than desirable, but it works just fine. e.g. { int n = getInt(); if(n > 10) { ... } } As it stands, there's a good chance that the comma operator is actually going to be _removed_ from the language (aside from specific use cases such as inside for loops). So, I don't think that there's much chance of it being expanded at all. - Jonathan M Davis
Re: Feature request: extending comma operator's functionality
On Thursday, 4 October 2012 at 21:17:51 UTC, Tommi wrote: Could you change it so that expressions, that are separated by commas and inside an if-clause, would have visibility to the variable defined in the first expression? Easier to show than to explain: [SNIP] A language change sounds excessive for something that simple blocks could fix: int getInt() { return 11; } void main() { { int n = getInt(); if (n > 10) // OK { //... } } { int n = getInt(); ++n; if (n > 10) // OK { //... } } { int n = getInt(); if (getInt() > 10) // OK { //... } } } Been doing this in C++ for a while actually.
Feature request: extending comma operator's functionality
Could you change it so that expressions, that are separated by commas and inside an if-clause, would have visibility to the variable defined in the first expression? Easier to show than to explain: int getInt() { return 11; } void main() { if (int n = getInt(), n > 10) // undefined identifier n { //... } if (int n = getInt(), ++n, n > 10) // undefined identifier n { //... } if (int n = getInt(), getInt() > 10) // OK { //... } } That would make it possible to define variables in the smallest possible scope, and not pollute the namespace of the enclosing scope.