digitalmars.D - "for" statement issue
- Andrei Alexandrescu (29/29) Oct 21 2016 I got a question about what happens with this code:
- Stefan Koch (5/10) Oct 21 2016 We could restrict the initialze part to assignments only. But I
- RazvanN (13/44) Oct 21 2016 I am the one who raised the question. I am n00b when it comes to
- Stefan Koch (7/21) Oct 21 2016 Ah.
- Adam D. Ruppe (14/16) Oct 21 2016 Eh, that's exactly what the language rules say should happen, and
- Stefan Koch (4/9) Oct 21 2016 Yes lets make it happen!
- Temtaime (5/12) Oct 21 2016 Please, no.
- Steven Schveighoffer (7/19) Oct 21 2016 No, it's not.
- mogu (30/55) Oct 21 2016 {} in swift is a lambda too. I think swift has better lambda
- Steven Schveighoffer (11/54) Oct 21 2016 We likely are not going to change the lambda syntax. However, it's
- mogu (13/13) Oct 21 2016 Allow new syntax makes codes simpler in some cases:
- Nick Treleaven (15/18) Oct 22 2016 Probably (a, b => a + b) could be legal. Reasoning:
- ag0aep6g (11/20) Oct 22 2016 How is it guaranteed that `a` doesn't have side effects? May be a
- Nick Treleaven (5/15) Oct 23 2016 I missed that case. (Insert grumble about non-UFCS parenthesis
- Timon Gehr (2/5) Oct 22 2016 It is. (It means pass a and the lambda b => a + b.)
- Andrei Alexandrescu (4/5) Oct 21 2016 Another possibility is to disallow an ExpressionStatement that consists
- Marc =?UTF-8?B?U2Now7x0eg==?= (7/14) Oct 22 2016 int j;
- Steven Schveighoffer (4/31) Oct 21 2016 How about in general forbidding lambda statements that aren't called or
- Kagamin (11/13) Oct 21 2016 How?
- Kagamin (1/1) Oct 21 2016 http://ideone.com/KBf8k9
- Steven Schveighoffer (8/20) Oct 21 2016 This lambda is both used in an assignment, and called.
- Steven Schveighoffer (7/19) Oct 21 2016 Oh, I see. This error that I didn't see right away wouldn't be
- Vladimir Panteleev (7/9) Oct 21 2016 For this specific case, a clear solution would be to forbid
- Andrei Alexandrescu (2/8) Oct 21 2016 Read the example again, the lambda is not evaluated as a bool. -- Andrei
- Vladimir Panteleev (4/6) Oct 21 2016 My bad.
I got a question about what happens with this code: int j; for({j=2; int d = 3; } j+d<7; {j++; d++;}) { } My first instinct was that that won't compile but it surprisingly does. And it loops forever. So the grammar according to https://dlang.org/spec/grammar.html#ForStatement is: ForStatement: for ( Initialize Testopt ; Incrementopt ) ScopeStatement Initialize: ; NoScopeNonEmptyStatement NoScopeNonEmptyStatement: NonEmptyStatement BlockStatement NonEmptyStatement goes over a bunch of odd places such as case statement and default statement. And then BlockStatement is the matched case: BlockStatement: { } { StatementList } So it seems we have another case in which "{" "}" do not introduce a scope. Fine. The real problem is with the increment part, which is an expression. The code { j++; d++; } is... a lambda expression that never gets used, which completes a very confusing sample. What would be a good solution to forbid certain constructs in the increment part of a for statement? Thanks, Andrei
Oct 21 2016
On Friday, 21 October 2016 at 12:34:58 UTC, Andrei Alexandrescu wrote:I got a question about what happens with this code: int j; for({j=2; int d = 3; } j+d<7; {j++; d++;}) { } [...]We could restrict the initialze part to assignments only. But I am unsure of the implications. How did you find this case?
Oct 21 2016
On Friday, 21 October 2016 at 12:34:58 UTC, Andrei Alexandrescu wrote:I got a question about what happens with this code: int j; for({j=2; int d = 3; } j+d<7; {j++; d++;}) { } My first instinct was that that won't compile but it surprisingly does. And it loops forever. So the grammar according to https://dlang.org/spec/grammar.html#ForStatement is: ForStatement: for ( Initialize Testopt ; Incrementopt ) ScopeStatement Initialize: ; NoScopeNonEmptyStatement NoScopeNonEmptyStatement: NonEmptyStatement BlockStatement NonEmptyStatement goes over a bunch of odd places such as case statement and default statement. And then BlockStatement is the matched case: BlockStatement: { } { StatementList } So it seems we have another case in which "{" "}" do not introduce a scope. Fine. The real problem is with the increment part, which is an expression. The code { j++; d++; } is... a lambda expression that never gets used, which completes a very confusing sample. What would be a good solution to forbid certain constructs in the increment part of a for statement? Thanks, AndreiI am the one who raised the question. I am n00b when it comes to D language (I just started reading about it a couple of days ago) and I tried the above mentioned code expecting that either the variables j and d get incremented accordingly or at least I would get a compilation error. Instead, the program compiles and when run it sticks into an infinite loop. I haven't read anything about lambda functions in D, but the current outcome is very confusing for a beginner like myself. Thanks, RazvanN
Oct 21 2016
On Friday, 21 October 2016 at 13:18:19 UTC, RazvanN wrote:On Friday, 21 October 2016 at 12:34:58 UTC, Andrei Alexandrescu wrote:Ah. It does create a lambda? Hmm that should not happen. I agree this is confusing and unwanted. Please feel free to post this to bugzilla. I will take a look next month. If nobody resolves it before then.[...]I am the one who raised the question. I am n00b when it comes to D language (I just started reading about it a couple of days ago) and I tried the above mentioned code expecting that either the variables j and d get incremented accordingly or at least I would get a compilation error. Instead, the program compiles and when run it sticks into an infinite loop. I haven't read anything about lambda functions in D, but the current outcome is very confusing for a beginner like myself. Thanks, RazvanN
Oct 21 2016
On Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:It does create a lambda? Hmm that should not happen.Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression. Though I have become convinced recently that we should deprecate the `{ lambdas }` in favor of `() { lambdas }`. This is the same mistake as `() => {xxx}` that we see a bunch of newbies make. If the syntax was changed to require the empty parens for the args, `() {}`, people would be a lot less likely to mess this up... and the rest of us don't seriously lose anything, adding `()` is easy enough if they aren't already there. I think deprecating `{ lambda }` is really the way to go. It'd fix this as well at that other FAQ at pretty low cost.
Oct 21 2016
On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:On Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:Yes lets make it happen! { } has too many meanings. Lets deprecate this one.It does create a lambda? Hmm that should not happen.I think deprecating `{ lambda }` is really the way to go. It'd fix this as well at that other FAQ at pretty low cost.
Oct 21 2016
On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:On Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:Please, no. It's fully clear that { stmts } createa a lambda, just () is ommited. foo({ code; }); is always OK and we shouldn't deprecate it.[...]Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression. [...]
Oct 21 2016
On 10/21/16 10:12 AM, Temtaime wrote:On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:No, it's not. { int x; x = 2; } Is not a lambda. It's a scope. So the meaning changes based on where it's used. I totally agree that we should remove that feature. -SteveOn Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:Please, no. It's fully clear that { stmts } createa a lambda, just () is ommited.[...]Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression. [...]
Oct 21 2016
On Friday, 21 October 2016 at 14:22:27 UTC, Steven Schveighoffer wrote:On 10/21/16 10:12 AM, Temtaime wrote:{} in swift is a lambda too. I think swift has better lambda syntax. Maybe could help for a better syntax in d. reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 }) reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } ) reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } ) reversedNames = names.sorted(by: { $0 > $1 } ) reversedNames = names.sorted(by: >) someFunctionThatTakesAClosure(closure: { // closure's body goes here }) someFunctionThatTakesAClosure() { // trailing closure's body goes here } let strings = numbers.map { (number) -> String in var number = number var output = "" repeat { output = digitNames[number % 10]! + output number /= 10 } while number > 0 return output }On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:No, it's not. { int x; x = 2; } Is not a lambda. It's a scope. So the meaning changes based on where it's used. I totally agree that we should remove that feature. -SteveOn Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:Please, no. It's fully clear that { stmts } createa a lambda, just () is ommited.[...]Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression. [...]
Oct 21 2016
On 10/21/16 10:38 AM, mogu wrote:On Friday, 21 October 2016 at 14:22:27 UTC, Steven Schveighoffer wrote:Swift doesn't have arbitrary scopes. So there is no ambiguity.On 10/21/16 10:12 AM, Temtaime wrote:{} in swift is a lambda too.On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:No, it's not. { int x; x = 2; } Is not a lambda. It's a scope. So the meaning changes based on where it's used. I totally agree that we should remove that feature.On Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:Please, no. It's fully clear that { stmts } createa a lambda, just () is ommited.[...]Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression. [...]I think swift has better lambda syntax. Maybe could help for a better syntax in d.We likely are not going to change the lambda syntax. However, it's possible we could remove the ambiguous cases.reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 }) reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } ) reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )(s1, s2) => s1 > s2 Seems pretty good to mereversedNames = names.sorted(by: { $0 > $1 } )With the original string lambdas, this was possible as "a > b". I'm not sure this case is worth much effort to add.reversedNames = names.sorted(by: >)Not sure if we'll ever get this in D :)someFunctionThatTakesAClosure(closure: { // closure's body goes here }) someFunctionThatTakesAClosure() { // trailing closure's body goes here }Yes, I've seen and used this. I think this is actually a little confusing. -Steve
Oct 21 2016
Allow new syntax makes codes simpler in some cases: writeln({ int a = 5; return a + 5; }()); => writeln{ int a = 5; return a + 5; }(); [1,2,3].fold!((a, b) => a + b).writeln; => [1,2,3].fold!{a, b => a + b}.writeln;
Oct 21 2016
On Friday, 21 October 2016 at 15:26:12 UTC, mogu wrote:[1,2,3].fold!((a, b) => a + b).writeln; => [1,2,3].fold!{a, b => a + b}.writeln;Probably (a, b => a + b) could be legal. Reasoning: 1. a could be an existing symbol in scope, otherwise it's an undefined identifier error. 2. If a was interpreted as an existing symbol which is followed by the comma operator, the expression (a) wouldn't have side effects so should be a compile error. 3. The bracketed comma expression would have to return the lambda b=>a+b as a value expression, which cannot compile because there are no arguments supplied for calling the lambda to obtain a value. So this syntax seems available as it isn't currently used for working code. A small change, maybe, but it's good to reduce bracket nesting to help with reading complex nested expressions. Destroy.
Oct 22 2016
On 10/22/2016 05:53 PM, Nick Treleaven wrote:Probably (a, b => a + b) could be legal. Reasoning: 1. a could be an existing symbol in scope, otherwise it's an undefined identifier error. 2. If a was interpreted as an existing symbol which is followed by the comma operator, the expression (a) wouldn't have side effects so should be a compile error.How is it guaranteed that `a` doesn't have side effects? May be a function call, since empty parentheses can be omitted in calls.3. The bracketed comma expression would have to return the lambda b=>a+b as a value expression, which cannot compile because there are no arguments supplied for calling the lambda to obtain a value.The lambda itself is a value, no? ---- int a() { import std.stdio; writeln("a"); return 1; } void main() { int delegate(int) dg = (a, b => a + b); } ----
Oct 22 2016
On Saturday, 22 October 2016 at 17:11:26 UTC, ag0aep6g wrote:How is it guaranteed that `a` doesn't have side effects? May be a function call, since empty parentheses can be omitted in calls.I missed that case. (Insert grumble about non-UFCS parenthesis omission being allowed).The lambda itself is a value, no? ---- int a() { import std.stdio; writeln("a"); return 1; } void main() { int delegate(int) dg = (a, b => a + b); }OK. Though AIUI from 2.072 a() must return void for the comma expression to compile (then a+b wouldn't compile either).
Oct 23 2016
On 22.10.2016 17:53, Nick Treleaven wrote:It is. (It means pass a and the lambda b => a + b.)[1,2,3].fold!{a, b => a + b}.writeln;Probably (a, b => a + b) could be legal.
Oct 22 2016
On 10/21/2016 09:42 AM, Adam D. Ruppe wrote:I think deprecating `{ lambda }` is really the way to go.Another possibility is to disallow an ExpressionStatement that consists solely of a lambda. There is precedent for that, e.g. the statement "1 + 1;" is disallowed. -- Andrei
Oct 21 2016
On Friday, 21 October 2016 at 13:42:49 UTC, Adam D. Ruppe wrote:On Friday, 21 October 2016 at 13:33:26 UTC, Stefan Koch wrote:int j; for({j=2; int d = 3; } j+d<7; {j++; d++;}) { } I'm more surprised by the fact that `d` is declared inside the first curly braces, but is evidently still in scope outside of it...It does create a lambda? Hmm that should not happen.Eh, that's exactly what the language rules say should happen, and it actually does make sense to me... you might even want to use an immediately-called lambda to group several statements together into one expression.
Oct 22 2016
On 10/21/16 8:34 AM, Andrei Alexandrescu wrote:I got a question about what happens with this code: int j; for({j=2; int d = 3; } j+d<7; {j++; d++;}) { } My first instinct was that that won't compile but it surprisingly does. And it loops forever. So the grammar according to https://dlang.org/spec/grammar.html#ForStatement is: ForStatement: for ( Initialize Testopt ; Incrementopt ) ScopeStatement Initialize: ; NoScopeNonEmptyStatement NoScopeNonEmptyStatement: NonEmptyStatement BlockStatement NonEmptyStatement goes over a bunch of odd places such as case statement and default statement. And then BlockStatement is the matched case: BlockStatement: { } { StatementList } So it seems we have another case in which "{" "}" do not introduce a scope. Fine. The real problem is with the increment part, which is an expression. The code { j++; d++; } is... a lambda expression that never gets used, which completes a very confusing sample. What would be a good solution to forbid certain constructs in the increment part of a for statement?How about in general forbidding lambda statements that aren't called or used anywhere? -Steve
Oct 21 2016
On Friday, 21 October 2016 at 14:16:26 UTC, Steven Schveighoffer wrote:How about in general forbidding lambda statements that aren't called or used anywhere?How? int main() { int a; auto b = ()=>{a++;}; b(); assert(a==1); return 0; }
Oct 21 2016
On 10/21/16 10:28 AM, Kagamin wrote:On Friday, 21 October 2016 at 14:16:26 UTC, Steven Schveighoffer wrote:This lambda is both used in an assignment, and called. If I do this: 10; It's flagged as not having any effect. Similarly if I do: () => 5; Then it's not used/called. What is the point? -SteveHow about in general forbidding lambda statements that aren't called or used anywhere?How? int main() { int a; auto b = ()=>{a++;}; b(); assert(a==1); return 0; }
Oct 21 2016
On 10/21/16 10:28 AM, Kagamin wrote:On Friday, 21 October 2016 at 14:16:26 UTC, Steven Schveighoffer wrote:Oh, I see. This error that I didn't see right away wouldn't be prevented, but that's not what I was talking about. I just meant that the original problem shouldn't have happened, since the lambda is never used. I totally agree that the above sucks and should be fixed. -SteveHow about in general forbidding lambda statements that aren't called or used anywhere?How? int main() { int a; auto b = ()=>{a++;}; b(); assert(a==1); return 0; }
Oct 21 2016
On Friday, 21 October 2016 at 12:34:58 UTC, Andrei Alexandrescu wrote:What would be a good solution to forbid certain constructs in the increment part of a for statement?For this specific case, a clear solution would be to forbid evaluating lambdas as a boolean expression, because they will always be true, and thus almost always an error. Same as with assignments in if statements. If intended, it can be worked around with "!is null".
Oct 21 2016
On 10/21/2016 12:39 PM, Vladimir Panteleev wrote:On Friday, 21 October 2016 at 12:34:58 UTC, Andrei Alexandrescu wrote:Read the example again, the lambda is not evaluated as a bool. -- AndreiWhat would be a good solution to forbid certain constructs in the increment part of a for statement?For this specific case, a clear solution would be to forbid evaluating lambdas as a boolean expression, because they will always be true, and thus almost always an error.
Oct 21 2016
On Friday, 21 October 2016 at 16:46:08 UTC, Andrei Alexandrescu wrote:Read the example again, the lambda is not evaluated as a bool. -- AndreiMy bad. In that case, what Steven said.
Oct 21 2016