Therefore I propose making such expressions a hard error in the compiler – this rules out all nondeterminism and naturally leads to more readable code. Failing that, we should at least provide a lint.
Unfortunately, derefs are everywhere and are not required to be pure (but hopefully nobody relies on the order of evaluation of impure derefs).
Until someone shows me a useful expression that cannot be expressed in Rust without relying on the order of evaluation, I stand by my point.
It is my intent that every expression is equivalent to one that is independent of the order of evaluation. However, a sane order-of-evaluation is important for ergonomics (also, not breaking every non-trivial Rust crate in the world).
I don't know if it impacts soundness at all, but my intuitive expection is that all method calls would be evaluated in the same order, so if its possible they should be the same I think.
This can't impact soundness as borrow checking will be done after simplification. I would prefer to do it for by-value method calls too.
Ok, it appears I overstepped here. &mut a[i] += &a[j] should be a lifetime error, though. So if the code after Deref coercion fails to appease borrowck, it won't compile today, no matter the evaluation order.
That is indeed a lifetime error under my rules. &mut a[i]
is an rvalue, so it is evaluated in one piece, before &a[j]
.
Thank you for pointing that out. I don't think it is too late, however, as evaluation order was deliberately unspecified, so code that depends on it is by definition erroneous.
The order of evaluation should be reasonable. I think "left to right, dereferences are evaluated as late as possible" is a reasonable rule.