digitalmars.D - D Logic bug
- James Japherson (11/11) Oct 11 2018 Took me about an hour to track this one down!
- rikki cattermole (8/28) Oct 11 2018 The specification makes this clear (even if another example is needed).
- krzaq (4/15) Oct 11 2018 Are any languages evaluating it differently? For example, is this
- Kagamin (4/6) Oct 11 2018 I don't think parentheses are ever treated like that. They are
- Shachar Shemesh (3/9) Oct 11 2018 Almost.
- Patrick Schluter (6/17) Oct 11 2018 As it should.
- Jonathan Marler (15/26) Oct 11 2018 In c++ the ternary operator is the second most lowest precedence
- Jonathan M Davis (8/43) Oct 11 2018 The operator precedence matches in D. Because in principle, C code shoul...
- Jonathan Marler (39/87) Oct 11 2018 I had a look at the table again, looks like the ternary operator
- Steven Schveighoffer (5/13) Oct 11 2018 Not in my C/D code. It would have copious parentheses everywhere :)
- Jonathan Marler (8/23) Oct 11 2018 Good :)
- Steven Schveighoffer (9/37) Oct 11 2018 Yep. General rule of thumb for me after having been burned many many
- Kagamin (3/17) Oct 12 2018 That's https://issues.dlang.org/show_bug.cgi?id=14186
- Steven Schveighoffer (3/24) Oct 12 2018 Wow, interesting that C precedence is different from C++ here.
- Patrick Schluter (3/10) Oct 12 2018 It's C++ which the anormal one.
- Patrick Schluter (8/45) Oct 12 2018 Please do not conflate C and C++. It is specifically on order of
- Nick Treleaven (8/17) Oct 15 2018 This is now deprecated:
- Neia Neutuladh (7/15) Oct 11 2018 Friends don't let friends use the ternary operator except in trivial cas...
- Jonathan M Davis (28/39) Oct 11 2018 When parens are used to affect operator precedence, it's _always_ by
- Patrick Schluter (6/11) Oct 12 2018 No, the off man out is C++. it's the only one with the priority
- Trass3r (5/9) Oct 11 2018 That's why shouldn't compose it like that.
Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.
Oct 11 2018
On 12/10/2018 3:35 AM, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.The specification makes this clear (even if another example is needed). The conditional expression takes an OrOrExpression not an expression as the condition. In other words, it requires a boolean operation on the left, with Expression's for the branches (deprecated behavior related to assignment for else branch but won't go into that). So not a bug and is working in a reasonable way. https://dlang.org/spec/expression.html#conditional_expressions
Oct 11 2018
On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.Are any languages evaluating it differently? For example, is this
Oct 11 2018
On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:In the ternary operator it should treat parenthesis directly to the left as the argument.I don't think parentheses are ever treated like that. They are self-contained and don't affect operators outside them.
Oct 11 2018
On 11/10/18 20:16, Kagamin wrote:On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:Almost. const(int) *In the ternary operator it should treat parenthesis directly to the left as the argument.I don't think parentheses are ever treated like that. They are self-contained and don't affect operators outside them.
Oct 11 2018
On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C;As it should.The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.No. Except for assignement and assignment operators, ternary operator has the lowest precedence of any operator in D (and C,
Oct 11 2018
On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.In c++ the ternary operator is the second most lowest precedence operator, just above the comma. You can see a table of each operator and their precendence here, I refer to it every so often: https://en.cppreference.com/w/cpp/language/operator_precedence Learning that the ternary operator has such a low precedence is one of those things that all programmers eventually run into...welcome to the club :) It looks like D has a similar table here (https://wiki.dlang.org/Operator_precedence). However, it doesn't appear to have the ternary operator in there. On that note, D would take it's precedence order from C/C++ unless there's a VERY good reason to change it.
Oct 11 2018
On Thursday, October 11, 2018 1:09:14 PM MDT Jonathan Marler via Digitalmars-d wrote:On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:The operator precedence matches in D. Because in principle, C code should either be valid D code with the same semantics as it had in C, or it shouldn't compile as D code, changing operator precedence isn't something that D is going to do (though clearly, the ternary operator needs to be added to the table). It would be a disaster for porting code if we did. - Jonathan M DavisTook me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.In c++ the ternary operator is the second most lowest precedence operator, just above the comma. You can see a table of each operator and their precendence here, I refer to it every so often: https://en.cppreference.com/w/cpp/language/operator_precedence Learning that the ternary operator has such a low precedence is one of those things that all programmers eventually run into...welcome to the club :) It looks like D has a similar table here (https://wiki.dlang.org/Operator_precedence). However, it doesn't appear to have the ternary operator in there. On that note, D would take it's precedence order from C/C++ unless there's a VERY good reason to change it.
Oct 11 2018
On Thursday, 11 October 2018 at 21:57:00 UTC, Jonathan M Davis wrote:On Thursday, October 11, 2018 1:09:14 PM MDT Jonathan Marler via Digitalmars-d wrote:I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D: a ? b : c = d In D it would be: (a ? b : c ) = d And in C++ would be: a ? b : (c = d) Check it out: --- import core.stdc.stdio; void main() { int a = 2, b = 3; printf("expr = %d\n", 1 ? a : b = 4); } --- prints "expr = 4" it evaluates the conditional (1 ? a : b) into the expression a, which is actually an rvalue! and then assigns it to 4 because of the "= 4" and then returns the value 4 to printf. Here's the C++ version: #include <stdio.h> int main(int argc, char *argv[]) { int a = 2, b = 3; printf("expr = %d\n", 1 ? a : b = 4); } This one prints "expr = 2" It simply returns the value of `a` because the "b = 4" at the end is all part of the "else" contition in the ternary operator.On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:The operator precedence matches in D. Because in principle, C code should either be valid D code with the same semantics as it had in C, or it shouldn't compile as D code, changing operator precedence isn't something that D is going to do (though clearly, the ternary operator needs to be added to the table). It would be a disaster for porting code if we did. - Jonathan M DavisTook me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.In c++ the ternary operator is the second most lowest precedence operator, just above the comma. You can see a table of each operator and their precendence here, I refer to it every so often: https://en.cppreference.com/w/cpp/language/operator_precedence Learning that the ternary operator has such a low precedence is one of those things that all programmers eventually run into...welcome to the club :) It looks like D has a similar table here (https://wiki.dlang.org/Operator_precedence). However, it doesn't appear to have the ternary operator in there. On that note, D would take it's precedence order from C/C++ unless there's a VERY good reason to change it.
Oct 11 2018
On 10/11/18 7:17 PM, Jonathan Marler wrote:I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D:Not in my C/D code. It would have copious parentheses everywhere :) That case is actually very strange, I don't know if it's something that's really common. -Steve
Oct 11 2018
On Thursday, 11 October 2018 at 23:29:05 UTC, Steven Schveighoffer wrote:On 10/11/18 7:17 PM, Jonathan Marler wrote:Good :)I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D:Not in my C/D code. It would have copious parentheses everywhere :)That case is actually very strange, I don't know if it's something that's really common.Yes, that explains why myself, Jonathan Davis and certainly others didn't know there were actually differences between C++ and D Operator precedence :) I wasn't sure myself but having a quick look at each's operator precedence table made it easy to find an expression that behaves differently in both.
Oct 11 2018
On 10/11/18 9:16 PM, Jonathan Marler wrote:On Thursday, 11 October 2018 at 23:29:05 UTC, Steven Schveighoffer wrote:Yep. General rule of thumb for me after having been burned many many times -- Always use parentheses to define order of operations when dealing with bitwise operations (and, or, xor) and for the ternary operator. I think I do make an exception when it's a simple assignment. i.e.: a = cond ? 1 : 2;On 10/11/18 7:17 PM, Jonathan Marler wrote:Good :)I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D:Not in my C/D code. It would have copious parentheses everywhere :)I actually was curious whether DMC followed the rules (hey, maybe Walter just copied his existing code!), but it does follow C's rules. -SteveThat case is actually very strange, I don't know if it's something that's really common.Yes, that explains why myself, Jonathan Davis and certainly others didn't know there were actually differences between C++ and D Operator precedence :) I wasn't sure myself but having a quick look at each's operator precedence table made it easy to find an expression that behaves differently in both.
Oct 11 2018
On Thursday, 11 October 2018 at 23:17:15 UTC, Jonathan Marler wrote:I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D: a ? b : c = d In D it would be: (a ? b : c ) = d And in C++ would be: a ? b : (c = d)That's https://issues.dlang.org/show_bug.cgi?id=14186
Oct 12 2018
On 10/12/18 6:06 AM, Kagamin wrote:On Thursday, 11 October 2018 at 23:17:15 UTC, Jonathan Marler wrote:Wow, interesting that C precedence is different from C++ here. -SteveI had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly. This is likely a result of the grammar differences rather than an intention one. For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D: a ? b : c = d In D it would be: (a ? b : c ) = d And in C++ would be: a ? b : (c = d)That's https://issues.dlang.org/show_bug.cgi?id=14186
Oct 12 2018
On Friday, 12 October 2018 at 13:15:22 UTC, Steven Schveighoffer wrote:On 10/12/18 6:06 AM, Kagamin wrote:It's C++ which the anormal one.On Thursday, 11 October 2018 at 23:17:15 UTC, Jonathan Marler wrote:Wow, interesting that C precedence is different from C++ here.[...]That's https://issues.dlang.org/show_bug.cgi?id=14186
Oct 12 2018
On Thursday, 11 October 2018 at 23:17:15 UTC, Jonathan Marler wrote:On Thursday, 11 October 2018 at 21:57:00 UTC, Jonathan M Davis wrote:Please do not conflate C and C++. It is specifically on order of precedence of the ternary that the 2 languages differ. It is C++ and only C++ which has the unconventionnal order of precedence where the ternary has the same priority as the assign operators. ALL other C derived languages have a higher priority for the ternary than the assignments.On Thursday, October 11, 2018 1:09:14 PM MDT Jonathan Marler via Digitalmars-d wrote:I had a look at the table again, looks like the ternary operator is on there, just called the "conditional operator". And to clarify, D's operator precedence is close to C/C++ but doesn't match exactly.On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:The operator precedence matches in D. Because in principle, C code should either be valid D code with the same semantics as it had in C, or it shouldn't compile as D code, changing operator precedence isn't something that D is going to do (though clearly, the ternary operator needs to be added to the table). It would be a disaster for porting code if we did. - Jonathan M Davis[...]In c++ the ternary operator is the second most lowest precedence operator, just above the comma. You can see a table of each operator and their precendence here, I refer to it every so often: https://en.cppreference.com/w/cpp/language/operator_precedence Learning that the ternary operator has such a low precedence is one of those things that all programmers eventually run into...welcome to the club :) It looks like D has a similar table here (https://wiki.dlang.org/Operator_precedence). However, it doesn't appear to have the ternary operator in there. On that note, D would take it's precedence order from C/C++ unless there's a VERY good reason to change it.
Oct 12 2018
On Thursday, 11 October 2018 at 23:17:15 UTC, Jonathan Marler wrote:For example, the "Conditional operator" in D actually has a higher priority than an assignment, but in C++ it's the same and is evaluated right-to-left. So this expression would be different in C++ and D: a ? b : c = d In D it would be: (a ? b : c ) = d And in C++ would be: a ? b : (c = d)This is now deprecated: int b = 1, c = 1; 1 ? b : c = 0; Deprecation: `1 ? b : c` must be surrounded by parentheses when next to operator `=` https://dlang.org/changelog/2.082.0.html#cond_assign
Oct 15 2018
On 10/11/2018 07:35 AM, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C;Friends don't let friends use the ternary operator except in trivial cases. This would be a good thing for a linter to check.The whole point of the parenthesis was to associate.Yes. The expression would otherwise have been parsed as: ((A + B) == 0) ? 0 : C It might be a good idea to deprecate arithmetic with booleans, which would have caught this specific error.
Oct 11 2018
On Thursday, October 11, 2018 8:35:34 AM MDT James Japherson via Digitalmars-d wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C; The whole point of the parenthesis was to associate. I usually explicitly associate precisely because of this! A + ((B == 0) ? 0 : C); In the ternary operator it should treat parenthesis directly to the left as the argument. Of course, I doubt this will get fixed but it should be noted so other don't step in the same poo.When parens are used to affect operator precedence, it's _always_ by enclosing the expression. There may be a language out there that does it a different way, but if so, I've never heard of it. Certainly, major languages the same kind of precedence for the ternary operator that D does. I honestly have no clue how you could ever have gotten the idea that putting parens in front of something could affect operator precedence, since I don't think that I've ever seen anything work that way in any language ever. By putting the parens around (B == 0), you've told the compiler to treat that as a single expression regardless of what operator precendence would otherwise do. You haven't told it to do anything to any other operators. So, A + B == 0 has gone from being equivalent to (A + B) == 0 to A + (B == 0) but that has no effect whatsoever on the ternary operator or any other operator that has lower precedence. So, really, it seems to me that your misunderstanding of operator precedence and parens goes well beyond the ternary operator. Normally, if someone were going to be confused by the operator precedence of the ternary operator, I'd expect them to be confused about the precendence of stuff that happens to the right of the ternary operator when it's in a more complicated expression, not about what happens with parens used in the condition. That stuff is the same as you'd get in any if statement or while loop condition. - Jonathan M Davis
Oct 11 2018
On Thursday, 11 October 2018 at 23:17:57 UTC, Jonathan M Davis wrote:On Thursday, October 11, 2018 8:35:34 AM MDT James Japherson via Digitalmars-d wrote:the way that D does, and they all have the same kind of precedence for the ternary operator that D does.No, the off man out is C++. it's the only one with the priority of the ternary equal to assignments. All other languages do it like C, i.e. with a higher priority for ?: C++ is the annoying one (as always) here.
Oct 12 2018
On Thursday, 11 October 2018 at 14:35:34 UTC, James Japherson wrote:Took me about an hour to track this one down! A + (B == 0) ? 0 : C; D is evaluating it as (A + (B == 0)) ? 0 : C;That's why shouldn't compose it like that. It's been a constant source of bugs in C/C++ code: https://www.viva64.com/en/b/0583/#ID0E1CAC
Oct 11 2018