// Assuming i, j and a[n] are all of some user-defined arithmetic type.
i = 0;
++i = ++i; // i = 1
j = 0;
(++j).operator=(++j); // j = 2
i = 0;
a[i] = ++i; // a[1] = 1, i = 1
j = 0;
a[j].operator=(++j); // a[0] = 1, j = 1
i = 1;
i <<= ++i; // i = 8
j = 1;
j = j << ++j; // j = 4
i = 0;
a[++i].f[++i](); // a[1].f[2]()
j = 0;
f[++j](a[++j]); // f[1](a[2]), which might actually call a[2].f[1]() per UFC
If I understand the status of the Expression Evaluation Order change in C++17 right, we will have inconsistency in C++ as below set in stone:
// Assuming i, j and a[n] are all of some user-defined arithmetic type.
i = 0;
++i = ++i; // i = 1
j = 0;
(++j).operator=(++j); // j = 2
i = 0;
a[i] = ++i; // a[1] = 1, i = 1
j = 0;
a[j].operator=(++j); // a[0] = 1, j = 1
i = 1;
i <<= ++i; // i = 8
j = 1;
j = j << ++j; // j = 4
And if you think about UFC (Unified Function Call):
i = 0;
a[++i].f[++i](); // a[1].f[2]()
j = 0;
f[++j](a[++j]); // f[1](a[2]), which might actually call a[2].f[1]() per UFC
On Sunday, September 4, 2016 at 5:03:28 PM UTC-4, mz wrote:If I understand the status of the Expression Evaluation Order change in C++17 right, we will have inconsistency in C++ as below set in stone:
// Assuming i, j and a[n] are all of some user-defined arithmetic type.
i = 0;
++i = ++i; // i = 1
j = 0;
(++j).operator=(++j); // j = 2
i = 0;
a[i] = ++i; // a[1] = 1, i = 1
j = 0;
a[j].operator=(++j); // a[0] = 1, j = 1
i = 1;
i <<= ++i; // i = 8
j = 1;
j = j << ++j; // j = 4
I disagree that those should be considered equivalent. The question is, what is the most likely intent of the writer of this code? Does a person who writes `a[i] = ++i` truly intend for it to behave like `a[i].operator=(++i)`?
The thinking behind the right-to-left rule for assignment operations is that a user who writes an assignment is thinking in terms of the right hand side happening first. That a user who writes `a[i] = ++i` is far more likely to expect the increment of `i` to happen before accessing the index of `a`. That's probably what they want to happen.
It also has to do with multiple assignment expressions, like `a[i] = i = 5;`. What does the user intend here? More likely than not, they intend to store `5` into `a[5]`.
On Sunday, September 4, 2016 at 5:03:28 PM UTC-4, mz wrote:If I understand the status of the Expression Evaluation Order change in C++17 right, we will have inconsistency in C++ as below set in stone:// Assuming i, j and a[n] are all of some user-defined arithmetic type.
i = 0;
++i = ++i; // i = 1
j = 0;
(++j).operator=(++j); // j = 2
i = 0;
a[i] = ++i; // a[1] = 1, i = 1
j = 0;
a[j].operator=(++j); // a[0] = 1, j = 1
i = 1;
i <<= ++i; // i = 8
j = 1;
j = j << ++j; // j = 4
I disagree that those should be considered equivalent. The question is, what is the most likely intent of the writer of this code? Does a person who writes `a[i] = ++i` truly intend for it to behave like `a[i].operator=(++i)`?
The thinking behind the right-to-left rule for assignment operations is that a user who writes an assignment is thinking in terms of the right hand side happening first. That a user who writes `a[i] = ++i` is far more likely to expect the increment of `i` to happen before accessing the index of `a`. That's probably what they want to happen.
It also has to do with multiple assignment expressions, like `a[i] = i = 5;`. What does the user intend here? More likely than not, they intend to store `5` into `a[5]`.
And if you think about UFC (Unified Function Call):
Which is not standard.
i = 0;
a[++i].f[++i](); // a[1].f[2]()
j = 0;
f[++j](a[++j]); // f[1](a[2]), which might actually call a[2].f[1]() per UFC
That's not how UFC works. `f[1](a[2])` cannot be transformed into `a[2].f[1]()`. UFC only works by the function's name. `f[1]` is an expression; it can only be called if it results in a callable type. So it will either be a function pointer or a type that has an `operator()` overload. Neither of which will provoke UFC.
FWIW, Nicol, my intuition disagrees with yours here. When I saw a[i] = i = 5, my brain said, "That's confusing... let me rewrite it as i = a[i] = 5; then it's a bit clearer what's happening.
The writer is clearly trying to store 5 into both a[i] and i." That is, my intuition, masquerading as common sense, says to me:(A) The effect of a multi-assignment a = b = c ought to be to give the value c to both a and b.(B) The notion of "a and b" ought to be equivalent to the notion "b and a": the notion of collecting things into a set has no intrinsic order.(C) Thus a[i] = i = 5 ought to mean something like setting both a[i] and i to 5.(D) Furthermore, a[i] = i = 5 ought to mean something different from a[5] = i = 5, because it looks different.Now, there's no technical reason for any of these (A-D) to be true; they're merely things that my reptile brain believes to be true. And thus it tricks me into thinking that a[i] = i = 5 is a meaningful expression whose meaning is roughly "set a[i] to 5; also (and obviously afterward), set i to 5." Now, this is not what the expression actually means in C++17; but it's going to take some time for my reptile brain to catch up with the modern world here.
On Sunday, September 4, 2016 at 7:25:06 PM UTC-7, Nicol Bolas wrote:On Sunday, September 4, 2016 at 5:03:28 PM UTC-4, mz wrote:If I understand the status of the Expression Evaluation Order change in C++17 right, we will have inconsistency in C++ as below set in stone:Certainly, but there's no harm in discussing it again. It's a topic that is both very confusing and very controversial, so it makes sense that lots of people want to talk about it.
a = b; // it shall mean 'a.operator=(b)', or equivalently, 'a.assign(b)', assuming this call returns the updated 'a'
a = b = c; // syntactically equivalent to 'a = (b = c)' under the established language rulesi = 4;
a[i] = i = 5; // interpreted as 'a[i] = (i = 5)'
// which is evaluated as 'a[4] = (i = 5)'
// which gives 'i = 5' and 'a[4] = 5'
i = 4;
i = a[i] = 5; // interpreted as 'i = (a[i] = 5)'
// which is evaluated as 'i = (a[4] = 5)'
// which gives 'i = 5' and 'a[4] = 5'Thanks for your reply. However I disagree on your arguements on "author's intention".
The key point is:
As long we are dealing any languages, what affects the communication is what your lines mean to the receiver, not what your intention behind them could be.
Even human can't read your mind. Compilers are just dumber. If you just stick to the language rules, there shouldn't be no confusion at all.
In simple cases, when one reads:a = b; // it shall mean 'a.operator=(b)', or equivalently, 'a.assign(b)', assuming this call returns the updated 'a'
How could one suppose anything different?
For chaining assignments, there is no logical problem with my proposed changes:a = b = c; // syntactically equivalent to 'a = (b = c)' under the established language rules
What does this mean semantically?
With my proposed rules, effectively every "lvalue" (that on let side of a '=') is evaluated before any assignment in the chain.
Remember that priority is not evaluation order, and the value of 'a @= b' is not the value of 'a', but the whole expression.
The meaning is definite and logical: first decide 'a' and 'b', then assign 'c' to both of 'b' and 'a' in the same line.
The subject of the action has to be decided before the action can take place. Isn't that intuitive?
Let's take this very example (all ssuming my proposed changes):i = 4;
a[i] = i = 5; // interpreted as 'a[i] = (i = 5)'
// which is evaluated as 'a[4] = (i = 5)'
// which gives 'i = 5' and 'a[4] = 5'
Let's question:
* The value of 'i' was 4 when the assignment line was reached. If one sees 'a[i]' written here, why shouldn't he assume 'a[4]' would be used?
* As FrankHB1989 quetioned, if one intended to mean 'a[5] = i = 5', why couldn't he write 'i = 5, a[i] = i' instead, to express the need for a sequence point?
Regarding UFC, none is standard at the moment, and I was talking about possible future additions, which could be more powerful than what has been proposed.
a = b = ca = (b = c)a.assign(b); // #1, evaluate a, evaluate b, and then assign b to a
a.operator=(b); // #2, evaluate a, evaluate b, and then assign b to a
a = b; // #3, this shall do the same thing as the abovea = b = ca.operator=(b.operator(c))I honestly have no idea what the supposed outcome of the last forum
discussion on this subject was,
if there was any outcome.
At this point, if someone wants to change
the direction the committee is going
towards, you really need an NB comment. I, however, will not file one
for you, because I don't disagree
with the current direction.
a || b && c; // same as 'a || (b && c)', but evaluated in the order as: a, b, c
a + b * c; // same as 'a + (b * c)', no specified evaluation order
a = b = c; // same as 'a = (b = c)', what order should it be in?a = b = c
// c, b, (b = c), a, a = EVA(b = c) per P0145R3
// a, b, c, (b = c), a = EVA(b = c) per my proposal
while yours on the other hand would be:
- you find your way more intuitive
You mentioned Operator Precedence.
Well, C++ is not a functional language, so that Evaluation Order matters, and Operator Associativity doesn't simply enforce the same Evaluation Order:a || b && c; // same as 'a || (b && c)', but evaluated in the order as: a, b, c
a + b * c; // same as 'a + (b * c)', no specified evaluation ordera = b = c; // same as 'a = (b = c)', what order should it be in?
(I am aware that you are concerning about the low-level implementation of Operator Precedence, but in the language level it isn't as important.)
Regarding language efficiency, the amount of evaluation work from the viewpoint of the language is the same in either order:a = b = c
// c, b, (b = c), a, a = EVA(b = c) per P0145R3
// a, b, c, (b = c), a = EVA(b = c) per my proposal
2016-09-06 8:58 GMT+04:30 mz <acq...@gmail.com>:You mentioned Operator Precedence.
Well, C++ is not a functional language, so that Evaluation Order matters, and Operator Associativity doesn't simply enforce the same Evaluation Order:a || b && c; // same as 'a || (b && c)', but evaluated in the order as: a, b, c
a + b * c; // same as 'a + (b * c)', no specified evaluation ordera = b = c; // same as 'a = (b = c)', what order should it be in?
(I am aware that you are concerning about the low-level implementation of Operator Precedence, but in the language level it isn't as important.)
Regarding language efficiency, the amount of evaluation work from the viewpoint of the language is the same in either order:a = b = c
// c, b, (b = c), a, a = EVA(b = c) per P0145R3
// a, b, c, (b = c), a = EVA(b = c) per my proposalThat is the point. Neglecting other aspects of the discussion, you are proposing to have 2 different sets of rules for evaluation order and operator precedence. For so dumb a person as me, 2 is a lot more complex to remember than 1.
One more tip: Idiomatic implementation of the assignment operator is to have 'return *this' as the last execution statement (which is consistent to operator precedence).I strongly believe that any evaluation order not following operator precedence, is source of great confusion.
I don't find it convincing at all that 'a[i] = i = 5' should be "intuitively evaluated right-to-left". Out of the 7 people who participates this discussion, 5 has commented on this 'a[i] = i = 5' example, and 3 of which disagrees on that "right-to-left is intuitive and clear". That's 3/5 = 60%.
Yeah, we have to pick a side. Once it's set in stone, it's hard to change. That's why I propose this fix, before it's really too late.
Then let's talk about your concern about "making them equivalent would lead to different evaluation orders".
With this example:a = b = c
No, I'd say this does NOT inherently imply right-to-left at all.
It's only certain that 'b = c' has to be evaluated before 'a = evaluated_value_of('b = c')' because the evaluation of the latter depends on the former, but evaluation of 'a' needn't depend on it.
In short: It's 'a = b = c' as a whole that has to be evaluated after 'b = c', not 'a' as a part that has to be evaluated after 'b = c'.
The required order here is part-then-whole, not right-to-left.
It is true that the expression is interpreted as:a = (b = c)
But this has only something to do with Operator Associativity, and nothing with Evaluation Orders.
So I'd say that "inherent right-to-left-ness of assignment" is just a false impression.
Then why should we go with left-to-right?
Just the motivating exmaple:a.assign(b); // #1, evaluate a, evaluate b, and then assign b to a
a.operator=(b); // #2, evaluate a, evaluate b, and then assign b to a
a = b; // #3, this shall do the same thing as the above
Since no one wants to change the evaluation order of 'a' and 'b' in #1 or #2 (as we desire chaining calls like 'x.then(y)'), only #3 can be changed.
Both of left-to-right and right-to-left orders may seem intuitive to some people and not to the other, but left-to-right has the advantage stated above over right-to-left: consistency.
Regards,FM.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ceaac1ed-717e-464b-9724-2973c0b62804%40isocpp.org.
People aren't compilers. Compilers should conform to the expectations of people, not the other way around. And if we decide that people are more likely to expect that `a = b` to evaluate `b` first, then that's what it should do.
a @ b; // evaluation order talks about 'a', 'b', and the whole expression, which to go first.
// Operator Associativity/Precedence talks about in what priority '@' can grab its operands, in this case 'a' and 'b',
// and there's no other operator to steal them.
a @ b $ c; // Precedence/Associativity decides whether '@' and '$' grabs only 'b' or the entire right/left-side subexpression.
// now we can talk about the "order" in which the two operations should be performed, which is a matter of only 'a @ ?' vs '? $ c'.
// none of the above requires any evaluation order of 'a', 'b' and 'c'.(a += b) *= c; // '+=' operates before '*=' because the latter's left operand is the result of the former.
a += (b *= c); // '+=' operates after '*=' because the former's right operand is the result of the latter.
a += b *= c; // the order of operations in this code is the same as the above simply because this line is interpreted as above.a ? b : c ? d : e; // Associativity: Right-To-Left, but Evaluation Order: 'a', 'b' or ('c', 'd' or 'e'), absolutely non-RTL!Two small things :
- When I see arr[i] = i = 5;, I personally expect RTL evaluation. The «intuitive» meaning some posters here give to this as evaluating arr[i] before i=5 seems extremely confusing to me. I hope there are better arguments than this one as it's extremely subjective
- On another level, when I see arr[i] = i = 5; I'm glad it seems like a weird and difficult statement to understand, and really wish we will not make efforts to turn this into idiomatic C++
That does not mean there's no argument in support of those pushing fixed expression ordering further than what we arrived at in Oulu, but I would be opposed if making code such as this modify-and-use-in-distinct-subexpressions easier to fathom was the goal of the proposal. Let's see if there are use cases we care to support as idiomatic C++ instead, to make this more productive. Things like:
int f(int&);int g(int&);int h() {int arg = 3;return f(arg) + arg + g(arg);}... are not things I'd care to fight in order to give definite meaning to. I'm sure those who want to make this sort of code meaningful can find examples that make this more appealing.
Cheers!
2016-09-06 11:37 GMT-04:00 FrankHB1989 <frank...@gmail.com>:
在 2016年9月6日星期二 UTC+8下午11:14:54,Farid Mehrabi写道:2016-09-06 8:58 GMT+04:30 mz <acq...@gmail.com>:You mentioned Operator Precedence.
Well, C++ is not a functional language, so that Evaluation Order matters, and Operator Associativity doesn't simply enforce the same Evaluation Order:a || b && c; // same as 'a || (b && c)', but evaluated in the order as: a, b, c
a + b * c; // same as 'a + (b * c)', no specified evaluation ordera = b = c; // same as 'a = (b = c)', what order should it be in?
(I am aware that you are concerning about the low-level implementation of Operator Precedence, but in the language level it isn't as important.)
Regarding language efficiency, the amount of evaluation work from the viewpoint of the language is the same in either order:a = b = c
// c, b, (b = c), a, a = EVA(b = c) per P0145R3
// a, b, c, (b = c), a = EVA(b = c) per my proposalThat is the point. Neglecting other aspects of the discussion, you are proposing to have 2 different sets of rules for evaluation order and operator precedence. For so dumb a person as me, 2 is a lot more complex to remember than 1.One more tip: Idiomatic implementation of the assignment operator is to have 'return *this' as the last execution statement (which is consistent to operator precedence).I strongly believe that any evaluation order not following operator precedence, is source of great confusion.Besides the original points here, I see your points broken. Operator precedence is a pure syntactic property of some (either well-formed or ill-formed) token sequence under some grammar, which has nothing to do with evaluation order on (well-formed) expressions. If the expression evaluation allows no side effects (i.e. so-called "purely functional"), the latter will have no effects on the result (e.g. normal order vs. applicative order), but the former still counts -- which is the typical cases for mathematical expressions. Since C++ allows side effects, this principle knowledge is more easily to be forgotten under noise and the illusion, which is exact the "source of great confusion". So they deserved to have to sets of rules.
Regards,FM.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e0222b6c-ddac-49aa-8caf-9f76beba278a%40isocpp.org.
Regards,FM.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ceaac1ed-717e-464b-9724-2973c0b62804%40isocpp.org.
2016-09-06 20:07 GMT+04:30 FrankHB1989 <frank...@gmail.com>:
在 2016年9月6日星期二 UTC+8下午11:14:54,Farid Mehrabi写道:2016-09-06 8:58 GMT+04:30 mz <acq...@gmail.com>:You mentioned Operator Precedence.
Well, C++ is not a functional language, so that Evaluation Order matters, and Operator Associativity doesn't simply enforce the same Evaluation Order:a || b && c; // same as 'a || (b && c)', but evaluated in the order as: a, b, c
a + b * c; // same as 'a + (b * c)', no specified evaluation ordera = b = c; // same as 'a = (b = c)', what order should it be in?
(I am aware that you are concerning about the low-level implementation of Operator Precedence, but in the language level it isn't as important.)
Regarding language efficiency, the amount of evaluation work from the viewpoint of the language is the same in either order:a = b = c
// c, b, (b = c), a, a = EVA(b = c) per P0145R3
// a, b, c, (b = c), a = EVA(b = c) per my proposalThat is the point. Neglecting other aspects of the discussion, you are proposing to have 2 different sets of rules for evaluation order and operator precedence. For so dumb a person as me, 2 is a lot more complex to remember than 1.One more tip: Idiomatic implementation of the assignment operator is to have 'return *this' as the last execution statement (which is consistent to operator precedence).I strongly believe that any evaluation order not following operator precedence, is source of great confusion.Besides the original points here, I see your points broken. Operator precedence is a pure syntactic property of some (either well-formed or ill-formed) token sequence under some grammar, which has nothing to do with evaluation order on (well-formed) expressions. If the expression evaluation allows no side effects (i.e. so-called "purely functional"), the latter will have no effects on the result (e.g. normal order vs. applicative order), but the former still counts -- which is the typical cases for mathematical expressions. Since C++ allows side effects, this principle knowledge is more easily to be forgotten under noise and the illusion, which is exact the "source of great confusion". So they deserved to have to sets of rules.A typical answer:cout << i << "," << ++i << flush;why in the first place the precedence and associativity rules were introduced? who and how (I mean the effort needed) to explain the difference of this two sets of rules to the experts(let alone the newbies trying to learn)?anyone who starts with C++ is supposed to learn precedence and associativity. and now you are going to impose another set of complex rules.cheers
Regards,FM.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ceaac1ed-717e-464b-9724-2973c0b62804%40isocpp.org.