Thread overview
NoNo for Associativity of Assignments?
Feb 23, 2007
Manfred Nowak
Feb 25, 2007
Joel C. Salomon
Feb 25, 2007
Manfred Nowak
Feb 25, 2007
Joel C. Salomon
Feb 26, 2007
Manfred Nowak
Feb 26, 2007
Stewart Gordon
February 23, 2007
Now that the associativity of comparisons has been dropped, I have the heart to point the readers attention to the associativity of assignments:

  There is no evaluation order specified for assignments.

From the specs:
| The right operand is implicitly converted to the type of the left
| operand, and assigned to it. The result type is the type of the
| lvalue, and the result value is the value of the lvalue after the
| assignment.
| The left operand must be an lvalue.

and

| It is an error to depend on order of evaluation when it is not | specified.


This means: "a = b = c;" is an error unless "a == b" and "b == c"!

But if both conditions hold "a = b = c;" is illegal:

| Expressions that have no effect, like (x + x), are illegal in
| expression statements.

Canonical solutions for this dilemma:
- drop associativity
- specify evaluation order

-manfred



February 25, 2007
Manfred Nowak wrote:
> Now that the associativity of comparisons has been dropped, I have
> the heart to point the readers attention to the associativity of
> assignments: 
> 
>   There is no evaluation order specified for assignments.
> 
> From the specs:
> | The right operand is implicitly converted to the type of the left
> | operand, and assigned to it. The result type is the type of the
> | lvalue, and the result value is the value of the lvalue after the
> | assignment. | The left operand must be an lvalue. 
> 
> and
> 
> | It is an error to depend on order of evaluation when it is not
> | specified. 
> 
> 
> This means: "a = b = c;" is an error unless "a == b" and "b == c"!

To my mind this means that in the expression
	a[f()] = b[g()] = h[()]
it is unspecified in which order f, g, and h are called; specifically, a[f()] may be evaluated to an lvalue before either of g or h is called, or after both, or “something else” and it’s an error to care.  Not sure where the ambiguity you’re claiming in
	a = b = c
can arise.

> Canonical solutions for this dilemma:
> - drop associativity

Bad idea; unlike the semantics for the comparison operators, the meaning of chained assignments is unambiguous to compiler and programmer alike.

> - specify evaluation order

Again, why does it matter if the lvalue-expression is obtained before or after the rvalue expression?  The grammar removes any ambiguity.

--Joel
February 25, 2007
Joel C. Salomon wrote
> the meaning of chained assignments is unambiguous to compiler and programmer alike.

Are you sure?

  int a=1, b=2, c=3;
  a = b = c;

With associativity this can virtually be rewritten as both
  ( a = b ) = c;
or
  a = ( b = c);

After "( a = b) = c;" a == 2, b == 3, c == 3.
After "a = ( b = c);" a == 3, b == 3, c == 3.

Of course one can _declare_ this to be unambigouous.

-manfred


February 25, 2007
Manfred Nowak wrote:
> Joel C. Salomon wrote
>> the meaning of chained assignments is unambiguous to compiler and
>> programmer alike. 
> 
> Are you sure?
> 
>   int a=1, b=2, c=3;
>   a = b = c;
> 
> With associativity this can virtually be rewritten as both
>   ( a = b ) = c;
> or
>   a = ( b = c);
> 
> After "( a = b) = c;" a == 2, b == 3, c == 3.
> After "a = ( b = c);" a == 3, b == 3, c == 3.
> 
> Of course one can _declare_ this to be unambigouous.

In C-like languages, assignment is right-associative; a = b = c /always/ is parsed as a = (b = c).

Also consider if (a = b) = c is even valid — does the expression (a = b) yield an lvalue?

--Joel
February 26, 2007
Joel C. Salomon wrote

> In C-like languages, assignment is right-associative; a = b = c
> /always/ is parsed as a = (b = c).

I have already posted what the specs for D say about evaluation order: no right associativity for assignments is given.

When evaluating "a[ 1] = a[ 2] = ... = a[n]" the compiler is allowed to choose any assignment "a[ i] = a [i+1]" for some valid i at random order for evaluation.

The compiler is free to store those assignments in an AA and then loop in a foreach over those assignments to execute them---or even distribute them over several cores to be faster.

Of course DMD does not do such currently.

-manfred
February 26, 2007
Manfred Nowak Wrote:

> Now that the associativity of comparisons has been dropped, I have the heart to point the readers attention to the associativity of assignments:
<snip>
> | It is an error to depend on order of evaluation when it is not | specified.
> 
> This means: "a = b = c;" is an error unless "a == b" and "b == c"!
<snip>

Your reasoning appears to be flawed.

a, b and c have no evaluation to be performed.  The only evaluations are of (b = c) and of (a = result).  The evaluation order _is_ specified: the result of (b = c) must be evaluated before it can be assigned to a.

Even if the lvalues do need to be evaluated, you're still not necessarily relying on evaluation order.

For example, for this:

    a[++i] = b[j -= 42] = c;

the evaluation order could be any topological sort of this graph:

++i ----------------> &a[++i] ---------------\
                                             +--> a[++i] = b[j -= 42] = c
j -= 42 --> &b[j -= 42] --> b[j -= 42] = c --/

Nowhere does what happens depend on which topological sort is chosen.  However, if we instead did

    a[++i] = b[i -= 42] = c;

then we have a problem, since the indexes used depend on which is evaluated first: (++i) or (i -= 42).


OST, I think what you're thinking is that, since the evaluation associativity of (a + b + c) is specified as unspecified, the same holds for = and other operators.  The bit I can find is

http://www.digitalmars.com/d/portability.html
"a + b + c
can be evaluated as (a + b) + c, a + (b + c), (a + c) + b, (c + b) + a, etc. Parentheses control operator precedence, parentheses do not control order of evaluation."

That is, the spec is effectively making an exception for + to the operator precedence implied by the grammar.  Unless I've missed it, the spec doesn't make any exception remotely resembling this for = or other operators.  (Strictly speaking, this isn't actually an exception, rather a possibility for optimisation.)

Stewart.