I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound" "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙ i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound" "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
i += 2 *= 3 -= 5 %= 11; // impossible in C and C++
(((i += 2) *= 3) -= 5) %= 11; // impossible in C, possible in C++
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound" "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
i += 2 *= 3 -= 5 %= 11; // impossible in C and C++
(((i += 2) *= 3) -= 5) %= 11; // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
On 04/11/2026 08:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
I don't see a distinction here between compound assignment and simple assignment - the compound assignment operators follow the simple
assignment operator for consistency, and because "x += y" is defined to
mean "x = x + y".˙ So I think that we can just talk about simple
assignment (or at least, talk about it first).
If you figure out (a), then (b) is the only possible choice.˙ That is,
if you write
˙˙˙˙x = y = z;
it could not be interpreted as
˙˙˙˙(x = y) = z;
unless "x = y" were an lvalue.
For simple assignment, if "x = y = z" were left associative, and "x = y" were an lvalue, that would mean that instead of being
˙˙˙˙y = z;
˙˙˙˙x = y;
it would now mean :
˙˙˙˙x = y;
˙˙˙˙x = z;
which is clearly not a useful construct.
(Personally, I'd rather that assignment had been a kind of statement
rather than an expression - but if a language is going to make
assignment an expression, it's better that it is a potentially useful one!)
I think that all covers (b) - why assignment (simple and compound) is right-associative.
Then there is (a) - why is the result of an assignment an rvalue, not an lvalue?˙ And why is it an lvalue in C++ ?
I don't know an answer to that, other than that I don't think there
would be any benefit of making it an lvalue in C.˙ (In C++, operators
can be overloaded and may do other things - making the result an lvalue
adds a little flexibility.)
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
On 2026-11-04, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
These properties make sense for the plain assignment operator,
for supporting x = y = z = 0. If this expression denoted a single
lvalue, that being x, then y and z would not receive any value,
and would have to be initialized: first x would be assigned the value
of y, then it would be assigned the value of z, and then zero.
The operational assignment operators were given the same properties as
plain assignment, without any thought of doing something usefully
different.
i += 2 *= 3 -= 5 %= 11; // impossible in C and C++
But
i += j += k *= 3
/is/ possible. k gets multiplied by 3, then its new value is added
to j, and the new value of j is added to i.
(((i += 2) *= 3) -= 5) %= 11; // impossible in C, possible in C++
Does that work for a basic type like int, and is it well-defined?
Possibly, under modern C++, a "sequenced before" requirement rescues
it, but I suspect that if we go back to C++98, it would have been
undefined: i is modified multiple times without an intervening sequence point.
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
i += 2 *= 3 -= 5 %= 11; // impossible in C and C++
(((i += 2) *= 3) -= 5) %= 11; // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
I think that one should look at the context. In the period when
C was born there were several attempts to define higher level or
portable assembly languages. If you look at say PL360 you will
see that its operations were chosen to directly translate to
360 operations. C is more abstract, but clearly constructs of
C were motivated by ability to get efficient machine code.
So various 'op=' operators were intended to correspond to
operations of typical 2 address machine. But as Kerningham and
Ritchie explanied there was second motivation: computing address
of left hand side may be a complex comutation and 'op=' operators
allow reuse of addressing computation. Now, let us look at
cascade that you want. You have a seqence of operations on
the same variable. If this variable in in machine register,
then naive translation leads to seqence of 2 address machine
instructions which is quite efficient. But writing this
as a sequence of separate C instructions leads to slightly
longer C code but identical machine code. If the variable
is in memory, then naive translation implies repeated
loads and stores which is clearly rather inefficient.
It is much more efficient to keep temporary result in
machine register and only assign final value and that is
easily done by writing complex expression and assigning
final result to variable. So, the example you gave is
code that Ritchie did not want. OTOH when you are computing
complex expression, then it may be quite useful to store
values of subexpressions for future use. That is why it
is natural to use value of assigment in future computations.
I think that the above reasonably explains associativity.
One could still make result to be lvalue, but by the above
argument lvalue is of limited use and it would require some
effort to efficiently support main use case, that is rvalue
case and true lvalue use. I guess that here simplicty
won: rvalue was needed and easy to implement, lvalue
offered little benefits but extra effort.
I do not know if this is substantial enough for you, but
for me it looks quite consistent with other early decisions
in C developement.
Thanks for your answer. (I'll keep all your explanations for context.)
My comments below...
On 2026-11-04 10:56, David Brown wrote:
On 04/11/2026 08:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
I don't see a distinction here between compound assignment and simple
assignment - the compound assignment operators follow the simple
assignment operator for consistency, and because "x += y" is defined
to mean "x = x + y".˙ So I think that we can just talk about simple
assignment (or at least, talk about it first).
Okay, I see where you're coming from. - Actually that reasoning is one
of the couple rationales that the AI provided me as answer as well.
Since I don't see the need to not have a distinction between = and op=
I dismissed that. In consequence, as you say or imply, all you derive
from that is thus also not convincing to me. - Let me expand on that...
First allow that I see = and op= as different things. (Note that, e.g.,
Algol 68 also differentiates here, so it's not a given that we handle
them the same or semantically similar.)
Allow having, at the design
stage, the option to just define the most sensible characteristics to
allow a consistent yet flexible use without "arbitrary" restrictions.
Given that cascading is considered useful and also used in practice I'd
like to consider that from another perspective; from use-cases.
What use-cases are there that would make it sensible to allow (in "C")
just rvalues, to prevent which misuses, or prevent what ambiguities, or
which problems with compilers, or would introduce any other problem?
What use-cases are there that would make it sensible to right-associate
(as in "C" and C++) modifications of an lvalue.
(Please keep in mind that there's yet no substantial need identified
to consider the two syntactic elements similar.)
I wouldn't think that a C-programmer would have difficulties to confuse semantics of = and op= (especially given that there's many a lot more confusing things in "C" as, e.g., the = and == choice). So "consistency"
is as argument vague at best.
I also understand what you wrote below that you'd preferred to not have
the issues in the first place by having "var op= val" being a statement.
(Since "C" is now actually returning a value the question remains why
the two properties - that I formulated as questions - were designed as
they are.)
A design where you can cascade the op= as a pipeline processing appears
quite appealing and natural to me (and I certainly used it; in C++ with
the parenthesis necessary, and in Algol 68 I used it straightforward).
So far on the general view "from outside".
If you figure out (a), then (b) is the only possible choice.˙ That is,
if you write
˙˙˙˙˙x = y = z;
it could not be interpreted as
˙˙˙˙˙(x = y) = z;
unless "x = y" were an lvalue.
Assignment with right-associativity I consider natural and all is fine.
For simple assignment, if "x = y = z" were left associative, and "x =
y" were an lvalue, that would mean that instead of being
˙˙˙˙˙y = z;
˙˙˙˙˙x = y;
it would now mean :
˙˙˙˙˙x = y;
˙˙˙˙˙x = z;
which is clearly not a useful construct.
Right, it's not a useful construct for assignments.
(Personally, I'd rather that assignment had been a kind of statement
rather than an expression - but if a language is going to make
assignment an expression, it's better that it is a potentially useful
one!)
All fine for assignments.
I think that all covers (b) - why assignment (simple and compound) is
right-associative.
And here, as mentioned already, I see the unnecessary (and design-wise artificial) equalization of the two distinct language atoms, = and op=.
Then there is (a) - why is the result of an assignment an rvalue, not
an lvalue?˙ And why is it an lvalue in C++ ?
I don't know an answer to that, other than that I don't think there
would be any benefit of making it an lvalue in C.˙ (In C++, operators
can be overloaded and may do other things - making the result an
lvalue adds a little flexibility.)
Yes, that's what I also think; it adds flexibility. And avoids an IMO unnecessary restriction; if there's any side-effect that matters in "C"
I've yet to see one or heard from one. That's why I was asking.
Janis
PS: It might help understanding why it appears natural to me, consider
its semantics "operate [sequentially] on a variable in an expression";
here an example with the two possible Algol 68 syntaxes
˙ number˙ TIMESAB base˙ PLUSAB digit
˙ number *:= base +:= digit
which in "C" would be
˙ number *= base;
˙ number += digit;
or
˙ number = number * base + digit
and in C++ either one of the "C" forms, or the parenthesized form
˙ (number *= base) += digit
So, in C/C++, two separate statements, variable duplication, spurious parenthesis. All adding to the often mentioned "cognitive load".
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound" "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙ i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
On 04/11/2026 07:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
Apparently this means:
˙˙˙˙ i := ((i + 2) * 3 - 5) %* 11
So it does not seem to buy you much. But doing it with ordinary
assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
˙ With a poor implementation, that will be less efficient
* There is less ambiguity, for example:
˙ i +:= 2 *:= i;
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
In my projects I don't allow such augmented or compound assignments to return any value at all. (It is too confusing, it is fiddly to
implement, and there are too many surprises.)
It is problematical in C too:
˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙ unsigned b = 200;
˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300. However you also see
that with ordinary chained assignments:
˙˙˙ a = b = c;
Both a and b end up with the value 44. So care is needed even here when terms are of mixed types.
On 04/11/2026 07:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
Apparently this means:
˙˙˙˙ i := ((i + 2) * 3 - 5) %* 11
So it does not seem to buy you much. But doing it with ordinary
assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
˙ With a poor implementation, that will be less efficient
* There is less ambiguity, for example:
˙ i +:= 2 *:= i;
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
In my projects I don't allow such augmented or compound assignments to return any value at all. (It is too confusing, it is fiddly to
implement, and there are too many surprises.)
It is problematical in C too:
˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙ unsigned b = 200;
˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300. However you also see
that with ordinary chained assignments:
˙˙˙ a = b = c;
Both a and b end up with the value 44. So care is needed even here when terms are of mixed types.
On 05/11/2026 13:17, bartc wrote:
It is problematical in C too:
˙˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙˙ unsigned b = 200;
Just to be clear - you meant "unsigned char b = 200;" here?
bartc pisze:
On 04/11/2026 07:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
Apparently this means:
˙˙˙˙˙ i := ((i + 2) * 3 - 5) %* 11
So it does not seem to buy you much. But doing it with ordinary
assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
˙˙ With a poor implementation, that will be less efficient
* There is less ambiguity, for example:
˙˙ i +:= 2 *:= i;
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
In my projects I don't allow such augmented or compound assignments to
return any value at all. (It is too confusing, it is fiddly to
implement, and there are too many surprises.)
It is problematical in C too:
˙˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙˙ unsigned b = 200;
˙˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300. However you also see
that with ordinary chained assignments:
˙˙˙˙ a = b = c;
Both a and b end up with the value 44. So care is needed even here
when terms are of mixed types.
btw it is some question if giving this arithmetic precedence
is good option
normally arithmetic goes sal yeft to right so you have
x=a+b*c˙ //5 chars
x=b*c+a˙ //5 chars
versus
x=(a+b)*c //7 chars
x=b*c+a˙˙ //5 chars
so the left to right would be shorter
im not saying thet the higher * precedence is bad, only worth noticing
its not the only option
On 05/11/2026 13:23, fir wrote:
bartc pisze:
On 04/11/2026 07:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior >>>> that other languages designed differently; specifically the "compound" >>>> "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties; >>>> (a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had >>>> mostly used C++, and I may have (wrongly!) assumed that "C" behaves the >>>> same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity. >>>>
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
Apparently this means:
˙˙˙˙˙ i := ((i + 2) * 3 - 5) %* 11
So it does not seem to buy you much. But doing it with ordinary
assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
˙˙ With a poor implementation, that will be less efficient
* There is less ambiguity, for example:
˙˙ i +:= 2 *:= i;
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
In my projects I don't allow such augmented or compound assignments
to return any value at all. (It is too confusing, it is fiddly to
implement, and there are too many surprises.)
It is problematical in C too:
˙˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙˙ unsigned b = 200;
˙˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300. However you also
see that with ordinary chained assignments:
˙˙˙˙ a = b = c;
Both a and b end up with the value 44. So care is needed even here
when terms are of mixed types.
btw it is some question if giving this arithmetic precedence
is good option
normally arithmetic goes sal yeft to right so you have
x=a+b*c˙ //5 chars
This is 7 characters in all. And normally it would be:
x=a+b*c;
which is 8 characters. Typically it will also be indented:
˙˙˙ x=a+b*c;
which is 9 characters with a single hard tab. Some also like to add
white space:
˙˙˙ x = a + b * c;
which is 15 characters.
x=b*c+a˙ //5 chars
versus
x=(a+b)*c //7 chars
x=b*c+a˙˙ //5 chars
so the left to right would be shorter
im not saying thet the higher * precedence is bad, only worth noticing
its not the only option
Different precedences for the /arithmetic/ operators are good (ie * /
are higher than + -) , because then the meaning aligns with how such expressions are universally understood, even in the real world.
Having to type () is not an imposition if they are necessary. The
character count is not too important (usually identifiers will be longer than single characters, plus see above); the number of tokens might be
more relevant, as well as () being shifted.
For the rest of the operators however C made some questionable choices
so that often you have to use () because (1) the less natural and useful choice was made, or (2) to make it clear what's happening because the precedences are obscure, unfamiliar or unintuitive, even if technically
not needed.
On 04/11/2026 07:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior
that other languages designed differently; specifically the "compound"
"and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
It might have been that it appeared not as serious to me because I had
mostly used C++, and I may have (wrongly!) assumed that "C" behaves the
same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity.
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
Apparently this means:
˙˙˙˙ i := ((i + 2) * 3 - 5) %* 11
So it does not seem to buy you much.
But doing it with ordinary assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
˙ With a poor implementation, that will be less efficient
* There is less ambiguity, for example:
˙ i +:= 2 *:= i;
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
In my projects I don't allow such augmented or compound assignments to return any value at all. (It is too confusing, it is fiddly to
implement, and there are too many surprises.)
It is problematical in C too:
˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙ unsigned b = 200;
˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300.
However you also see
that with ordinary chained assignments:
˙˙˙ a = b = c;
Both a and b end up with the value 44. So care is needed even here when terms are of mixed types.
On 05/11/2026 03:19, Janis Papanagnou wrote:
Thanks for your answer. (I'll keep all your explanations for context.)
My comments below...
On 2026-11-04 10:56, David Brown wrote:
On 04/11/2026 08:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior >>>> that other languages designed differently; specifically the "compound" >>>> "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two properties; >>>> (a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
I don't see a distinction here between compound assignment and simple
assignment - the compound assignment operators follow the simple
assignment operator for consistency, and because "x += y" is defined
to mean "x = x + y".˙ So I think that we can just talk about simple
assignment (or at least, talk about it first).
Okay, I see where you're coming from. - Actually that reasoning is one
of the couple rationales that the AI provided me as answer as well.
Since I don't see the need to not have a distinction between = and op=
I dismissed that. In consequence, as you say or imply, all you derive
from that is thus also not convincing to me. - Let me expand on that...
I can agree that op= does not /need/ to be consistent with simple
assignment for associativity and rvalue/lvalue results, but I think a language designer would need very strong reasons before allowing them to
be inconsistent.
First allow that I see = and op= as different things. (Note that, e.g.,
Algol 68 also differentiates here, so it's not a given that we handle
them the same or semantically similar.)
Okay.˙ I am quite happy to accept that and see where it leads us.˙ (Note that I have almost no knowledge of Algol 68, if that is relevant.)
Allow having, at the design
stage, the option to just define the most sensible characteristics to
allow a consistent yet flexible use without "arbitrary" restrictions.
Okay.
Given that cascading is considered useful and also used in practice I'd
like to consider that from another perspective; from use-cases.
Cascading is also considered unclear and questionable style, with poorly defined semantics in special cases (such as volatile accesses) or if
there are other side effects involved.
Different people will have different opinions on what should be allowed
or disallowed in a language - and when they are willing to disallow some useful cases to ensure dangerous cases are compile-time errors, or when
they are willing to allow some dangerous cases to ensure that useful
cases are allowed.
However the balance is picked for a language, it is inevitable that some potentially useful cases will be disallowed in order to reduce the risk
of subtle errors in code.
What use-cases are there that would make it sensible to allow (in "C")
just rvalues, to prevent which misuses, or prevent what ambiguities, or
which problems with compilers, or would introduce any other problem?
Perhaps my imagination is lacking.
For simple assignment, I can't think of any.˙ "(a = b) = c;", if it were allowed in C, would mean the same as "a = b; a = c;" except that "a" is
only evaluated once.
(Imagine "a" was "xs[i++]" to see why that matters.)
The only reason to write "a = b; a = c;" would be for the
side-effects, such as if "b" and "c" are function calls or volatile variables.˙ And I cannot see any circumstances where "(a = b) = c;"
would be seen as clearer than "b; a = c;" or - if you want it as a
single expression - "b, a = c;".
For compound assignment, "(a += b) += c;" would mean (ignoring multiple evaluations of "a") :
˙˙˙˙a = a + b;
˙˙˙˙a = a + c;
The only circumstances I can think of where "(a += b) += c" would be preferable to "a += (b + c)", is if the calculation order affected
signed integer overflow or rounding in floating point.˙ And then I think
the code would be far better written as "a = (a + b) + c;".
What use-cases are there that would make it sensible to right-associate
(as in "C" and C++) modifications of an lvalue.
In C++, functions can return references that are lvalues.˙ Operators can
be overloaded for user types, as functions.˙ It is therefore consistent
in the language that the result of assignment operators is an lvalue.
But I don't see use-cases for lvalue results of assignment operators on standard types.
(Please keep in mind that there's yet no substantial need identified
to consider the two syntactic elements similar.)
I wouldn't think that a C-programmer would have difficulties to confuse
semantics of = and op= (especially given that there's many a lot more
confusing things in "C" as, e.g., the = and == choice). So "consistency"
is as argument vague at best.
"C is so confusing that it doesn't matter if we make it worse" does not carry much weight with me.˙ Again - I think it would be fine to have an inconsistency between simple and compound assignment, but only if there
was a very strong reason /for/ the inconsistency.˙ So far, you have not given any reason that I can see.
I also understand what you wrote below that you'd preferred to not have
the issues in the first place by having "var op= val" being a statement.
(Since "C" is now actually returning a value the question remains why
the two properties - that I formulated as questions - were designed as
they are.)
A design where you can cascade the op= as a pipeline processing appears
quite appealing and natural to me (and I certainly used it; in C++ with
the parenthesis necessary, and in Algol 68 I used it straightforward).
Could you give some examples of how you use it in C++?˙ That would, I
think, make it a lot clearer to me why you think this is a good idea.
So far on the general view "from outside".
If you figure out (a), then (b) is the only possible choice.˙ That
is, if you write
˙˙˙˙˙x = y = z;
it could not be interpreted as
˙˙˙˙˙(x = y) = z;
unless "x = y" were an lvalue.
Assignment with right-associativity I consider natural and all is fine.
For simple assignment, if "x = y = z" were left associative, and "x =
y" were an lvalue, that would mean that instead of being
˙˙˙˙˙y = z;
˙˙˙˙˙x = y;
it would now mean :
˙˙˙˙˙x = y;
˙˙˙˙˙x = z;
which is clearly not a useful construct.
Right, it's not a useful construct for assignments.
(Personally, I'd rather that assignment had been a kind of statement
rather than an expression - but if a language is going to make
assignment an expression, it's better that it is a potentially useful
one!)
All fine for assignments.
I think that all covers (b) - why assignment (simple and compound) is
right-associative.
And here, as mentioned already, I see the unnecessary (and design-wise
artificial) equalization of the two distinct language atoms, = and op=.
Then there is (a) - why is the result of an assignment an rvalue, not
an lvalue?˙ And why is it an lvalue in C++ ?
I don't know an answer to that, other than that I don't think there
would be any benefit of making it an lvalue in C.˙ (In C++, operators
can be overloaded and may do other things - making the result an
lvalue adds a little flexibility.)
Yes, that's what I also think; it adds flexibility. And avoids an IMO
unnecessary restriction; if there's any side-effect that matters in "C"
I've yet to see one or heard from one. That's why I was asking.
Janis
PS: It might help understanding why it appears natural to me, consider
its semantics "operate [sequentially] on a variable in an expression";
here an example with the two possible Algol 68 syntaxes
˙˙ number˙ TIMESAB base˙ PLUSAB digit
˙˙ number *:= base +:= digit
which in "C" would be
˙˙ number *= base;
˙˙ number += digit;
or
˙˙ number = number * base + digit
and in C++ either one of the "C" forms, or the parenthesized form
˙˙ (number *= base) += digit
So, in C/C++, two separate statements, variable duplication, spurious
parenthesis. All adding to the often mentioned "cognitive load".
Multiple statements, duplicated variables and additional parentheses can
all /reduce/ cognitive load sometimes - though they certainly can
increase it in other cases.˙ Overly compact code is just as bad as
overly verbose code.
If I saw "(number *= base) += digit;" in a code review, I would reject
it as "smart-arse" coding.
My preference would be something like :
˙˙˙˙const auto scaled_number = unscaled_number * base + digit;
My strong preference in coding is to initialise variables once, not
modify them unless it really is helpful (or necessary, such as for
loops).˙ Unnecessary multiple modifications of one variable in one expression?˙ No thanks.
However, that is /my/ preference - other people like to do things differently.˙ /My/ personal preferences were not a deciding factor in
the design of C or C++ !
It might have been that it appeared not as serious to me because I had >>>> mostly used C++, and I may have (wrongly!) assumed that "C" behaves the >>>> same way. But sadly, no, they differ here.
˙˙ i += 2 *= 3 -= 5 %= 11;˙˙˙˙˙˙˙ // impossible in C and C++
˙˙ (((i += 2) *= 3) -= 5) %= 11;˙ // impossible in C, possible in C++
But C++ still requires parentheses because of the right-associativity. >>>>
(I suppose the rvalue to lvalue semantical design variant in C++ was
to facilitate such cascades?
And the left-associativity was maybe considered to be too drastic a
change compared to the (partly) inherited "C" design?
But my primary question here is about the "C" design rationale!)
Note: My question is not about possible workarounds. (I know them.)
Janis
[*] I emphasized "substantial" because what the Google AI "explained"
to me wasn't at all convincing.
PS: Algol 68 (for example) had also a left-associativity which allows
˙˙ i +:= 2 *:= 3 -:= 5 %*:= 11
and given that the "C" authors knew that language but deviated from
that paragon there must (or might) have been some thoughts about why
it is as it is?
On 2026-11-05 13:17, bartc wrote:
We still have the advantages that I mentioned elsethread. But that
was not my question.
I remind: since they have introduced op= to return a value why did
they do it the way they did. Specifically, what are the use-cases
that they support by their implementation semantics (with rvalues
and right-associativity).
But doing it with ordinary assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
This appears to me to be nonsensical given that we are talking about abstractions in a higher-level language, and that the transformation
to machine instructions need not even result in different code.
˙˙ With a poor implementation, that will be less efficient
With poor implementation everything will be less efficient.
number *:= base +:= digit
The task doesn't matter. The behaviour needs to be well-defined. And˙˙ i +:= 2 *:= i;
What is that supposed to implement in the first place is the question!
I suggest to explain a sensible task,
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
Are you now speaking about a left-associative interpretation?
Anyway, you seem to not see the obvious change of 'i' with '+:=', so
I cannot help you.
I understand that it is confusing to you. I understand that you seem
to consider it to be "fiddly". I understand that you are incapable of defining a clear semantics
so that it won't surprise anyone.
It is problematical in C too:
˙˙˙˙ int˙˙˙˙˙ a = 1000;
˙˙˙˙ unsigned b = 200;
˙˙˙˙ int˙˙˙˙˙ c = 300;
˙˙˙˙ a += b += 100;
'a' ends up with the value 1044 rather than 1300.
Are you hallucinating?
On 05/11/2026 22:41, Janis Papanagnou wrote:[...]
On 2026-11-05 13:17, bartc wrote:
˙˙ i +:= 2 *:= i;
What is that supposed to implement in the first place is the question!
I suggest to explain a sensible task,
The task doesn't matter.
The behaviour needs to be well-defined.
And here that might be unintuitive.
The second 'i' will have the new value i + 2, not the original, even
though it has not obviously been modified.
Are you now speaking about a left-associative interpretation?
I'm speaking about observed behaviour from A68G:
˙INT i:=100;
˙i +:= 2 *:= i;
˙print(i)
Output is 10404, or 102 * 102. It is not the same as either of:
˙ i := i + 2 * i;˙˙˙˙˙˙ # 300 #
˙ i := (i + 2) * i;˙˙˙˙ # 10200 #
It is also confusing in that here:
˙ number *:= base +:= digit
It looks as though 'base' is being modified too.
[ snip another, yet more pathological example with side-effects ]
I understand that it is confusing to you. I understand that you seem
to consider it to be "fiddly". I understand that you are incapable of
defining a clear semantics
The point is that the semantics are necessarily more obscure and less obvious compared with plain code which only has one assignment.
so that it won't surprise anyone.
I understand that you've never had to implement any of this stuff.
[...]
On 2026-11-05 11:33, David Brown wrote:
On 05/11/2026 03:19, Janis Papanagnou wrote:
Thanks for your answer. (I'll keep all your explanations for context.)
My comments below...
On 2026-11-04 10:56, David Brown wrote:
On 04/11/2026 08:53, Janis Papanagnou wrote:
I just stumbled about something in "C" where I knew there was behavior >>>>> that other languages designed differently; specifically the "compound" >>>>> "and-becomes" operators (+=, -=, *=, /=, %=).
I'm basically looking for substantial[*] rationales for two
properties;
(a) that their result is an rvalue (and not an lvalue), and
(b) that their evaluation in cascades has right-associativity.
I don't see a distinction here between compound assignment and
simple assignment - the compound assignment operators follow the
simple assignment operator for consistency, and because "x += y" is
defined to mean "x = x + y".˙ So I think that we can just talk about
simple assignment (or at least, talk about it first).
Okay, I see where you're coming from. - Actually that reasoning is one
of the couple rationales that the AI provided me as answer as well.
Since I don't see the need to not have a distinction between = and op=
I dismissed that. In consequence, as you say or imply, all you derive
from that is thus also not convincing to me. - Let me expand on that...
I can agree that op= does not /need/ to be consistent with simple
assignment for associativity and rvalue/lvalue results, but I think a
language designer would need very strong reasons before allowing them
to be inconsistent.
You may have missed that I don't consider it "inconsistent". (The
reasons have already been explained.)
(I understood that with your _equalization_ of the = and op= classes
of operators you find it "inconsistent". As an opinion I accept it.)
Given that cascading is considered useful and also used in practice I'd
like to consider that from another perspective; from use-cases.
Cascading is also considered unclear and questionable style, with
poorly defined semantics in special cases (such as volatile accesses)
or if there are other side effects involved.
Here you are speaking about 'volatile' in "C", right? - I've not
engaged with 'volatile' deeply enough to comment on that. - I'm
only asking whether that's a problem with the 'volatile' concept
or the op= logic as it's defined. (And whether 'volatile' and the
op= question is the only problem here - i.e. the "bad feature" is
the op= - where 'volatile' won't show any other problems with all
the other "C" constructs.)
Concerning _side-effects_ is a general
problem in "C"; bart has in a recent post made up a side-effect
sample (to criticize op= , not to criticize writing side-effects).
Different people will have different opinions on what should be
allowed or disallowed in a language - and when they are willing to
disallow some useful cases to ensure dangerous cases are compile-time
errors, or when they are willing to allow some dangerous cases to
ensure that useful cases are allowed.
(Well, sure. That's why I asked for [sensible] use-cases.)
However the balance is picked for a language, it is inevitable that
some potentially useful cases will be disallowed in order to reduce
the risk of subtle errors in code.
(Still not obvious what that actually would be. - No offense intended
but sounds more like FUD. That's why I asked for something concrete.)
I can't see how op= expressions with rvalues and right-associativity semantics would in any way be [significantly] more "risky" than the
C-form with lvalues and right associativity, or the C++-form with
rvalues and right-associativity.
What use-cases are there that would make it sensible to allow (in "C")
just rvalues, to prevent which misuses, or prevent what ambiguities, or
which problems with compilers, or would introduce any other problem?
Perhaps my imagination is lacking.
Mine as well. - That's why I was asking; if we'd have a convincing
example it could answer my original question. (So I can meanwhile
just speculate that it might be the reason that also Kaz mentioned
in his post.)
The only circumstances I can think of where "(a += b) += c" would be
preferable to "a += (b + c)", is if the calculation order affected
signed integer overflow or rounding in floating point.˙ And then I
think the code would be far better written as "a = (a + b) + c;".
I'm not sure what the sample with '+' and '+=' serves here. (I'd have
thought my example with mixed operations would fit better explaining
things; it was:˙ number *= base += digit; .)
WRT˙ "a = (a + b) + c;"˙ I'd just repeat my key-words: duplication and parentheses. In "C" you have anyway only the choices already mentioned,
so just use what's existing.
What use-cases are there that would make it sensible to right-associate
(as in "C" and C++) modifications of an lvalue.
In C++, functions can return references that are lvalues.˙ Operators
can be overloaded for user types, as functions.˙ It is therefore
consistent in the language that the result of assignment operators is
an lvalue. But I don't see use-cases for lvalue results of assignment
operators on standard types.
I see the additional advantages for C++.
And I see use-cases for lvalues in "C". (See above.)
(Please keep in mind that there's yet no substantial need identified
to consider the two syntactic elements similar.)
I wouldn't think that a C-programmer would have difficulties to confuse
semantics of = and op= (especially given that there's many a lot more
confusing things in "C" as, e.g., the = and == choice). So "consistency" >>> is as argument vague at best.
"C is so confusing that it doesn't matter if we make it worse" does
not carry much weight with me.˙ Again - I think it would be fine to
have an inconsistency between simple and compound assignment, but only
if there was a very strong reason /for/ the inconsistency.˙ So far,
you have not given any reason that I can see.
You probably got me wrong; I wasn't asking for a change of "C".
Could you give some examples of how you use it in C++?˙ That would, I
think, make it a lot clearer to me why you think this is a good idea.
Sorry, I can provide no production code; my professional C++ days were
in the 1990's and I have no access to the code. All I remember was that
I occasionally used such cascades, and that I had to write "spurious" parenthesis to achieve the left-associativity.
So, in C/C++, two separate statements, variable duplication, spurious
parenthesis. All adding to the often mentioned "cognitive load".
Multiple statements, duplicated variables and additional parentheses
can all /reduce/ cognitive load sometimes - though they certainly can
increase it in other cases.˙ Overly compact code is just as bad as
overly verbose code.
Yes, I agree.
If I saw "(number *= base) += digit;" in a code review, I would reject
it as "smart-arse" coding.
Well, that's obviously the effect when one is reviewing code based on
one's personal opinion rather than based on a coding standard document
which has rules with rationales associated to every rule.
(None of the various coding standards I was involved in creating had a "smart-arse" type of "rationale".)
My preference would be something like :
˙˙˙˙˙const auto scaled_number = unscaled_number * base + digit;
Different use-case. My code was an excerpt from incrementally creating
the number in a loop. Here's some Algol 68 code for _illustration_ only
(i.e. non-optimized, and using the verbose word-operators instead of
the terse forms, just written just for the post)
˙˙˙ STRING numstr = "12345";
˙˙˙ INT number := 0;
˙˙˙ FOR i TO UPB numstr DO
˙˙˙˙˙˙˙ number˙ TIMESAB 10˙ PLUSAB (ABS numstr[i] - ABS "0")
˙˙˙ OD
Another cascade I was recently writing (with two 'op=' "pipelines") was
˙˙˙ FOR i FROM 1 TO UPB key DO
˙˙˙˙˙˙˙ hash˙ PLUSAB ABS key[i] * pp˙ MODAB hash_modulus;
˙˙˙˙˙˙˙ pp˙˙˙ TIMESAB p˙˙˙˙˙˙˙˙˙˙˙˙˙˙ MODAB hash_modulus
˙˙˙ OD
My strong preference in coding is to initialise variables once, not
In case of 'op=' you *have* to initialize the variable on the LHS!
modify them unless it really is helpful (or necessary, such as for
loops).˙ Unnecessary multiple modifications of one variable in one
expression?˙ No thanks.
However, that is /my/ preference - other people like to do things
differently.˙ /My/ personal preferences were not a deciding factor in
the design of C or C++ !
That applies to most people. :-)
But it's noteworthy, IMO, if you saw discrepancies or infelicities in
a language, and while you can't actually do anything about it, you see
that then changed in some standard two decades later. Or if you see
some time later that the authors of a language are self-critically
speaking about such cases. - All this makes it worthwhile to discuss
the state of things, languages, tools, and standards. - And don't just
accept things as "final wisdom".
Janis
PS: I noticed that you repeated things in your post that I had already
been answering. I answered them again in case they were overlooked.
But it makes no sense to continue the subthread that way.
On 05/11/2026 22:41, Janis Papanagnou wrote:
On 2026-11-05 13:17, bartc wrote:
We still have the advantages that I mentioned elsethread. But that
was not my question.
I remind: since they have introduced op= to return a value why did
they do it the way they did. Specifically, what are the use-cases
that they support by their implementation semantics (with rvalues
and right-associativity).
Algol68 had this big idea that everything has to return some value, >including compound assignment. Given that, it made these choices, which >includes ordinary assignment having RTL precedence, and compound
assignment being LTR.
Personally I don't see any great need to allow compound assignments to
be chained at all, as it only leads to harder-to-understand code with
too many things being updated within the same statement.
So my compound assignments return 'void'.
But doing it with ordinary assignment has some advantages:
* Only one assignment is done, not 4 lots of /compound/ assignments.
This appears to me to be nonsensical given that we are talking about
abstractions in a higher-level language, and that the transformation
to machine instructions need not even result in different code.
˙˙ With a poor implementation, that will be less efficient
With poor implementation everything will be less efficient.
number *:= base +:= digit
I did a brief speed test using A68G. That version was 50% slower than:
number := number * base + digit;
| Sysop: | Tetrazocine |
|---|---|
| Location: | Melbourne, VIC, Australia |
| Users: | 4 |
| Nodes: | 8 (0 / 8) |
| Uptime: | 190:54:24 |
| Calls: | 222 |
| Files: | 21,513 |
| Messages: | 85,912 |