P0145R3: Expression Evaluation Order leads to inconsistency?

275 views
Skip to first unread message

mz

unread,
Sep 4, 2016, 5:03:28 PM9/4/16
to ISO C++ Standard - Future Proposals
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


That is to say, I found both the '@=' right-to-left and 'f(x)' f-then-x orders problematic, as they make surposedly equivalent expressions different.
Thing would look consistent if they are inverted:

#1 'a @= b': a then b
#2 'f(a0, a1, a2, ..., an)': a0, a1, a2, ..., an (I'm OK if unspecified ordering is still desired), then f

As regard to 'a.f(b)', while I know it's syntactically '(a.f)(b)', but in UFC's sense it's semantically 'f(a, b)', so #2 with stronger ordering of 'a0' will be sufficient.

With these changes the example above will all give consistent results, even future-proof (for UFC).

What do you guys think? Too late?

Nicol Bolas

unread,
Sep 4, 2016, 10:25:06 PM9/4/16
to ISO C++ Standard - Future Proposals


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.

There's no way that `expr(...)` can undergo UFC. It only works if you have `name(...)`.

Arthur O'Dwyer

unread,
Sep 4, 2016, 11:25:43 PM9/4/16
to ISO C++ Standard - Future Proposals
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.
 
 
 
// 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]`.

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.

I think it's perfectly reasonable for people to point out such things. Although obviously they'd be more effective as National Body comments instead of forum posts. ;)

my $.02,
–Arthur

FrankHB1989

unread,
Sep 4, 2016, 11:36:53 PM9/4/16
to ISO C++ Standard - Future Proposals


在 2016年9月5日星期一 UTC+8上午10:25:06,Nicol Bolas写道:


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)`?
They should have to, because this is how the operator overloading rules work.

Simple syntactic sugar already works well.

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.

Value computation in assignments evaluated right-to-left because this is the only sane choice of defined order in general, due to the value dependency implied by the semantics of assignment. (Yes, I don't think left-to-right is sane; unless they are rewritten like mov in AT&T assembly.)

BTW, I'm still not convinced every side effect here should be sequenced because to make arbitrary expression evaluated without UB for C++ is simply not the intent anywhere. The more obvious problem in reality is that a sanity check is often missing for the writer before the more serious damage occur. A user who writes it without the cognition above should not expect anything. Probable only threats of UB can be the lesson.


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]`.
 
No excessive side effects; this works well.
 
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.

Things like `operator++` are unqualified names, if well-formed. And [over.oper] interprets expressions with overloaded operator by equivalent postfix-expressions with operator-function-id. Not read much about UFC proposals, not sure how UFC will work around this. But anyway, if [over.oper] is special, UFC will look like not that "unified".

Message has been deleted

FrankHB1989

unread,
Sep 5, 2016, 12:13:26 AM9/5/16
to ISO C++ Standard - Future Proposals
在 2016年9月5日星期一 UTC+8上午11:25:43,Arthur O'Dwyer写道:


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.

I will never write multiple = in a single full expression unless necessary, e.g. propagate change on `volatile` lvalues by specific order. For other cases, the clear one is to use something (e.g. spelled unseq) indicates I clearly don't need to depend on the order of the side effects (and it can be actually implemented portably when there is no void involved).

Both a[i] = i = 5 and i = a[i] = 5 are confusing and they have made me really confused for a while. I guess you need i = 5 and a[5] = 5 ? Then I why not unseq(i = 5, a[5] = 5)or simply just i = 5; a[i] = 5 (only i is not volatile-qaulified)? Note the former may be not the best solution here since multiple occurrence of same right operand violates DRY, but it is still better when the equal value is introduced accidentally (yeah, you can't notice this easily), and to implement a "broadcast" assignment (hmm... indeed SIMD) is another story.

D. B.

unread,
Sep 5, 2016, 3:39:18 AM9/5/16
to std-pr...@isocpp.org
On Mon, Sep 5, 2016 at 4:25 AM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
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.
 

Actually, it sort of is harmful to just discuss it idly here at the moment, when - as you implied - time is running out to file an NB comment if it bothers anyone that much.

Also, I would normally caution against duplicate threads, especially if this incarnation were to have the same low signal-to-noise ratio that the last one did.

 

mz

unread,
Sep 5, 2016, 3:46:23 AM9/5/16
to ISO C++ Standard - Future Proposals
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?

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'

And same results as the previous example gave, as the meaning suggests.
In 'daily' sense, first decide 'i' and 'a[i]', then 'a[i] = 5' and 'i = 5' in the same line.

I fail to see any problem here.

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.

在 2016年9月5日星期一 UTC上午2:25:06,Nicol Bolas写道:

Domen Vrankar

unread,
Sep 5, 2016, 4:22:29 AM9/5/16
to std-pr...@isocpp.org
> 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?
>
> 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'
>
> And same results as the previous example gave, as the meaning suggests.
> In 'daily' sense, first decide 'i' and 'a[i]', then 'a[i] = 5' and 'i = 5'
> in the same line.
>
> I fail to see any problem here.

My problem with such changes to the proposal is that while it is
intuitive for some of you the opposite is intuitive for me:
i = 4;
a[i] = i = 5; // interpreted as 'a[i] = (i = 5)'
// which is evaluated as 'a[5] = (i = 5)' <- since i
gets the value of 5 in the mean time
// which gives 'i = 5' and 'a[5] = 5'

That is intuitive to me since every change to a declared variable has
its effects later on.

This reasoning looks to me like the one with curly braces - whether
they should be on the same line as if/for/function or on the next one
- but with one difference: With your proposal you require a temporary
variable representing the previous value of i.

When I look at that line of code I expect to see operator precedence
being honored by evaluation order and view the statement like this:

i gets a register space that is set to 5
a with offset of register which represents i is loaded into second
register and is set to 5 as well

so since content of register representing i has changed in the mean
time I expect that to be visible in the parts of the statement that
get evaluated later.

So I'm guessing that my arguments are:
- I find my way more intuitive
- it requires one temporary variable less

while yours on the other hand would be:
- you find your way more intuitive

So when it comes to one intuitiveness to the other we get to poor
arguments as you'll probably find the same amount of people feeling
one way or the other.

I stopped reading the other thread a while ago since it felt to me as
'I want this without a special reason except my gut feeling regarding
intuitiveness' argument so I don't know what the conclusion there was
but I do hope that if this thread will go further your arguments would
be a bit better than playing the intuitiveness card.

Regards,
Domen

Nicol Bolas

unread,
Sep 5, 2016, 11:17:18 AM9/5/16
to ISO C++ Standard - Future Proposals
On Monday, September 5, 2016 at 3:46:23 AM UTC-4, mz wrote:
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.

That kind of thinking is what landed us in this mess to begin with.

We've proven that people don't "stick to the language rules". Otherwise, there wouldn't be a need to define an order for operations. We would all remember that these operations are unordered and spell everything out manually.

But people don't do that. Why? Because people have expectations which exist outside of the language. And they will follow those expectations rather than the language.

Forcing users to follow those expectations does not work. Therefore, forcing the language to follow user expectations is more likely to eliminate bugs.

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?

Because you didn't actually write `a.operator=(b)`.

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.

Even if that means that `a.operator=(b)` would have evaluated `a` first. The transformation from one to the other merely describes how you find the function. It does not describe how you evaluate the argument expressions.

Same goes for any UFC shenanigans.

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?

When you see `a[i] = i = 5`, you see two distinct operations: `i = 5` and `a[i] = result`, in that order. That's read right-to-left. So it makes sense that the evaluation of the sub-expressions takes place in that order.

What you're effectively saying is that you should evaluate the sub-expressions in one order, then evaluate the assignment operations in a different order. That's... strange.

* 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?

I could just as easily say the reverse: if you intended to assign `5` to i and assign a[4]` the value of 5, why not write it that way: `i = a[i] = 5`?

That's the thing; neither ordering denies you any expressive power. You can rewrite the multiple assignment to achieve the effect you want.

But we need to pick a side. So the way I would pick a side is to see which way people are more likely to expect it to work.

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.

UFC could be a lot of things. But until we know what it actually will be, we shouldn't start making changes to otherwise reasonable functionality based on what might happen in the future.

I've seen what happens when standards committees start trying to predict the future. It doesn't end well.

Ville Voutilainen

unread,
Sep 5, 2016, 11:42:43 AM9/5/16
to ISO C++ Standard - Future Proposals
On 5 September 2016 at 18:17, Nicol Bolas <jmck...@gmail.com> wrote:
> On Monday, September 5, 2016 at 3:46:23 AM UTC-4, mz wrote:
>>
>> 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.
>
>
> That kind of thinking is what landed us in this mess to begin with.
>
> We've proven that people don't "stick to the language rules". Otherwise,
> there wouldn't be a need to define an order for operations. We would all
> remember that these operations are unordered and spell everything out
> manually.
>
> But people don't do that. Why? Because people have expectations which exist
> outside of the language. And they will follow those expectations rather than
> the language.
>
> Forcing users to follow those expectations does not work. Therefore, forcing
> the language to follow user expectations is more likely to eliminate bugs.

Indeed. For those inclined to rehash that part of this discussion, do read
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0145r1.pdf
again, and specifically the example in it:

void f()
{
std::string s = "but I have heard it works even if you don't believe in it";
s.replace(0, 4, "").replace(s.find("even"), 4, "only").
replace(s.find(" don't"), 6, "");
assert(s == "I have heard it works only if you believe in it");
}

That code wouldn't have been written by people who "stick to language
rules". That code,
however, was looked at by an expert after an expert, and everybody who
read it more or less
thought "OF COURSE that's valid, and IT'S OBVIOUS that it works".
Well, it works as expected
when compiled by a C++17 compiler. With a pre-C++17 compiler, it does
quite the opposite
of what is expected by the users.

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.

mz

unread,
Sep 5, 2016, 10:27:01 PM9/5/16
to ISO C++ Standard - Future Proposals
I am afraid you lost track here.

The main goal of my proposal is to fix the inconsistency in semantics introduced by P0145R3 (accepted with a change in Oulu), while keeping achiving the same goals P0145R3 aims for.

I don't find this proposal contrary to the good motivation and goals of P0145R3. Instead, I find the inconsistency introduced by P0145R3 contrary to.

My fix neither conflict with your example that you want to make working. With my fix applied, your example will work "as intended".

The debate on 'intuitiveness of chaining assignments' is not settled yet. We'll see how it's going on.

If you are wrorried about the "rule vs intention" issue, my reasoning is:
We may change the rule if it's inappropriate. But once we have set up a language rule, we have to follow it in order to communicate successfully, until we change it again.

As we are looking forward to using C++17, we have to follow the rule set in it, until we change it next time.

mz

unread,
Sep 5, 2016, 10:32:25 PM9/5/16
to ISO C++ Standard - Future Proposals
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.

If we just require left-to-right-ness, then there's only one same order. Things are just simpler and more consistent.


Are these really equivalent?

I'd say we can keep them equivalent.


a = b = c

Two assignments occurs:
* First, the assignment 'b = c' takes place.
* Then, the assignment 'a = evaluated_value_of('b = c')' takes place.

The order these two things happens EXACTLY MATCHES with the operator call form:

a.operator=(b.operator(c))

The two forms are just doing exactly the same thing with regards to the assignments, in the same order.
Is there any reason why they should differ each other? What difference would a coder expect?

If there's no good reason to make them different, things will be easier if we just make them equivalent.


在 2016年9月5日星期一 UTC下午3:17:18,Nicol Bolas写道:

FrankHB1989

unread,
Sep 5, 2016, 11:46:19 PM9/5/16
to ISO C++ Standard - Future Proposals


在 2016年9月5日星期一 UTC+8下午11:42:43,Ville Voutilainen写道:
No. OF COURSE it's of bad smell to me and someone else. Whether it is semantically valid or not, it is meaningless here; I will not generate any serious code in such style; it will not pass my review and I will not let it exist in my codebase except some test cases. That check is prior to sanity checks based on the language rules, so unless I have to implement some deterministic diagnostics in tools, I am not interested in arguing if it is correct merely according to the language rules. And repeatedly, please note there are more elegant (at least to me and someone else, in the sense of clarity, etc), indisputably workable and portable replacements. Even it had been actually broken by the language rules, it should not shock the one who are not relying on it deliberately too much. So why are you assuming it SHOULD work for everyone?

NOTE: I don't force to change the language rules just to reject code I don't want to see, because I know it is not the right place and there exists more effective way. I don't know how do you think about it exactly, but the change do disturb me a lot (by introducing more work on documentation and potentially QA for users of the language in future, without any actual benefits), so I am strongly against it. Or do you want to turn the standard into a coding guideline? Good luck.
 
I honestly have no idea what the supposed outcome of the last forum
discussion on this subject was,
if there was any outcome.
Knowing there are different views more seriously, probably.
 
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.
True, but things other than than to "change the direction the committee is going towards" have turned into more important. (Ah, teachability counts, again.) JTC1 (if not WG21) should have known how to getting a consensus-based approach work.

Anyway, I don't think the standard has ability to force any coding style in projects I am dealing with before it is approved to be a national one, being mandated by local laws (e.g. GB18030 in mainland China). That direction just makes me more busy for some other kinds of work, sooner or later :) ... though significantly more expensive:(

FrankHB1989

unread,
Sep 5, 2016, 11:59:53 PM9/5/16
to ISO C++ Standard - Future Proposals


在 2016年9月6日星期二 UTC+8上午10:27:01,mz写道:
The last sentence is not totally true. You can draft the specification you want by patching on the based one. You have not to follow all of the based specification and we have experience of this approach long time ago, e.g. the keyword `export`.

However, this change is more serious as it may have effect about forcing the change on default configuration of implementations and conformance guarantees in many real projects (hmm... to keep so called bug-to-bug compatibility bidirectionally -- both forward & backward... if we finally settled out which one is more buggy here), so the cost will be much higher. So the debates remains.

mz

unread,
Sep 6, 2016, 12:28:09 AM9/6/16
to ISO C++ Standard - Future Proposals
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 order
a = 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

If "register/memory efficiency" is a problem then we have the same problem with 'a[i].f(i = 5)'. Do we want right-to-left-ness for this?
Moreover, it doesn't make quite much sense to directly compare the efficiency if the code does different things (like 'i++' vs '++i').


while yours on the other hand would be:
- you find your way more intuitive

- And more consistent in language rules. That''s the main point.

Farid Mehrabi

unread,
Sep 6, 2016, 11:14:54 AM9/6/16
to std-proposals
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 order
a = 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


  ​That 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. 

Regards,
FM.

Nicol Bolas

unread,
Sep 6, 2016, 11:22:10 AM9/6/16
to ISO C++ Standard - Future Proposals
On Tuesday, September 6, 2016 at 11:14:54 AM UTC-4, Farid Mehrabi wrote:
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 order
a = 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


  ​That 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.

Operator precedence rules aren't changing. All we're doing is making expression evaluation order follow operator associativity rules.

That's 1 rule: expressions evaluate in the order defined by the operator's associativity. Equality operators associate RTL, therefore their expressions evaluate that way too.
 
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.

Then you seem to be arguing for RTL evaluation ordering, since that follows operator='s associativity.

Nicol Bolas

unread,
Sep 6, 2016, 11:25:39 AM9/6/16
to ISO C++ Standard - Future Proposals
On Monday, September 5, 2016 at 10:32:25 PM UTC-4, mz wrote:
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.

But you haven't shown it to be broken. Even if we assume 5 people are a statistically significant sample size, 60% is hardly sufficient reason to overturn a decision that's already been made.

My overall feeling on the matter is this: if it were changed to LTR, I wouldn't lose any sleep over it. I'm more concerned about having an order than the exact order used. However, RTL for equality operators gained consensus in the standards committee, probably for a very good reason. To overturn that consensus should require an overriding concern. And I don't feel that this issue of having `a = b` not evaluating the same way as `a.operator=b` rises to that level.

I don't believe users will be baffled or confused by RTL equality operator ordering. I don't believe users will by and large be surprised or stupefied by it. I do not believe that it will be particularly difficult to teach.

And that's good enough for me.

Then let's talk about your concern about "making them equivalent would lead to different evaluation orders".

... that's not my concern. Indeed, I searched this thread, and nobody here made that statement. So who are you responding to?

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.

"False impression" or not, it's still there. It's still an impression. In order to understand what the expression `a = b = c` does, you have to read it right to left.

What you seem to want is to make someone read it left-to-right then right-to-left. That's... inconsistent.

Note that this is different from your above example of `a || b && c`. The difference being that this one uses different operators with different precedences. Whereas `a = b = c` is one operator precedence, who's associativity is right-to-left.

Evaluation order should match the associativity of an operator. Associativity defines how you read an expression, so evaluation order ought to match it.

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.

You achieve consistency of transforming `a = b` into its functional form, at the cost of consistency with the assignment operator's associativity. The point being that you're going to break consistency one way or the other. Why should we prefer this form of consistency over the other?

FrankHB1989

unread,
Sep 6, 2016, 11:37:55 AM9/6/16
to ISO C++ Standard - Future Proposals


在 2016年9月6日星期二 UTC+8下午11:14:54,Farid Mehrabi写道:
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.

Patrice Roy

unread,
Sep 6, 2016, 12:34:45 PM9/6/16
to std-pr...@isocpp.org
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!

--
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.

Edward Catmur

unread,
Sep 7, 2016, 10:27:09 AM9/7/16
to ISO C++ Standard - Future Proposals
On Monday, 5 September 2016 16:17:18 UTC+1, Nicol Bolas wrote:
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.
 
Isn't that why we have tiered optimization levels? -O3 pretty much means "compile what I wrote, even if it violates my expectations".

Mathias Stearn

unread,
Sep 7, 2016, 11:53:37 AM9/7/16
to ISO C++ Standard - Future Proposals
I think this discussion is focusing too much on example code that we all seem to agree is poorly written. How about the more common and subtle case of associative containers and exceptions. Should this function offer the the strong exception guarantee or should it leave the map with a new value-constructed entry if an exception is thrown?

std::map<std::string, int> myMap;

const int& loadValueOrThrow(const std::string& key) {
    return myMap[key] = computeSomethingOrThrow(key);
}

Note that adopting pure LTR order makes the following usage of that function wrong:

const int& cachedValueOrThrow(const std::string& key) {
    auto it = myMap.find(key);
    if (it != myMap.end()) return it->second;
    return loadValueOrThrow(key);
}
Message has been deleted

mz

unread,
Sep 8, 2016, 6:57:58 PM9/8/16
to ISO C++ Standard - Future Proposals
Honestly, I had some confusion with how Associativity and Precedence are defined (not translated well into my native language). After some careful thoughts I think this should be clarified better:
  • Evaluation Order decides an order of (sub-)expressions.
  • Operator Associativity and Precedence decide how the code is interpreted as if adding parentheses into the expression. Associativity decides how among operators in the same Precedence group, and Precedence decides how among the groups.
Examples to show the difference between the concepts in detail:

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'.

It's the operands of the operator and the result of the operation evaluated, not the operator itself:

(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.


As you may have noticed, Associativity and Precedence are virtually the same concept, but there's no Precedence defined LTR or RTL at all. Isn't this a hint for something? And even if you still want Evaluation Order to analogize Associativity, here's the dreaded Ternary Conditional Operator that cannot be "fixed":

a ? b : c ? d : e; // Associativity: Right-To-Left, but Evaluation Order: 'a', 'b' or ('c', 'd' or 'e'), absolutely non-RTL!

If consistency would be broken one way or another, I would choose to break the already imperfect consistency between two different concepts (Operator Associativity and Evaluation Order), instead of the perfect consistency of one concept (Operator Evaluation Order) as well as the consistency of equivalent operations (Operator Form vs Operator's Function Call Form).

I think the choice is obvious.

在 2016年9月6日星期二 UTC下午3:25:39,Nicol Bolas写道:

mz

unread,
Sep 8, 2016, 7:05:28 PM9/8/16
to ISO C++ Standard - Future Proposals
If you care about memorability, in my opinion it would be easier with my proposed changes (ignoring the still unspecified ones):

* Only one evaluation order for operands with all operators (LTR).
* Only one evaluation order for operands with operators and their corresponding function calling forms (LTR).
* Two operator associativity/precedences for binary operators (LTR vs RTL).
* Different operator associativity vs evaluation orders ('@=' and '?:').

If we still to status quo (ignoring the still unspecified ones too):

* Two evaluation orders for operators (LTR vs RTL).
* Two evaluation orders for '@=' operators and their corresponding function forms (RTL vs LTR).
* Two operator associativity precedences for binary operators (LTR vs RTL).
* And still different operator associativity vs evaluation orders ('?:').

[sarcasm] May it feels more consistent if everything has two variants? [/sarcasm]


在 2016年9月6日星期二 UTC下午3:14:54,Farid Mehrabi写道:

D. B.

unread,
Sep 8, 2016, 7:11:37 PM9/8/16
to std-pr...@isocpp.org
So in addition to the previous thread that would not go away, in which a couple of people just continually repeated the same points, now we have a 2nd copy of it. Good to know.

Get onto a National Body and file a comment against the draft Standard. Or write a really convincing proposal rather than idly debating here. Otherwise, it's just noise.

FrankHB1989

unread,
Sep 9, 2016, 12:09:29 AM9/9/16
to ISO C++ Standard - Future Proposals


在 2016年9月7日星期三 UTC+8上午12:34:45,Patrice Roy写道:
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:

I realized that RTL on assignments is preferred for more people. I don't think any implicit order rules should be relied on here (like expressions with possibly unevaluated operands), but RTL here seems plausible and more reasonable than LTR.
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.

I'm afraid making such code be meaningful in production is horrible. To modify same lvalue without explicit order more than once is error-prone with readability bad enough (even there is no UB), anyway.
 
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 order
a = 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


  ​That 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.

Farid Mehrabi

unread,
Sep 15, 2016, 1:25:00 PM9/15/16
to std-proposals
​I know that. the post was a response to the O.P . but thanks anyway. 
And it is not equality , it is assignment. equality refers to comparison.
 
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.



--
how am I supposed to end the twisted road of  your hair in such a dark night??
unless the candle of your face does shed some light upon my way!!!

Farid Mehrabi

unread,
Sep 15, 2016, 1:41:29 PM9/15/16
to std-proposals
​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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

FrankHB1989

unread,
Sep 18, 2016, 12:20:00 AM9/18/16
to ISO C++ Standard - Future Proposals


在 2016年9月16日星期五 UTC+8上午1:41:29,Farid Mehrabi写道:


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 order
a = 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


  ​That 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

There are no rules about "precedence" or "associativity" normatively in C++. In fact, they are not specific to C++. Every infix grammar can have such rules. And in C++, they can be applied on other syntactic categories, not only "expressions". However, the descriptions based on "precedence" or "associativity" is totally optional and still absolutely incomplete for formal C++ syntax. So newbies should probably just forget them if they are learning C++ rather than some formal grammars of languages in general; they should read the syntax notation instead, as well as some other rules to disambiguate some obscure cases.

I learned C++ by myself and I did not take care about so-called precedence and associativity at all. I have seen many people got stuck on them (and many of them even did not know what is "syntax", properly), but I was luckily not :)

 
 

 
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.
Reply all
Reply to author
Forward
0 new messages