When people try to explain the compound assignment operators += –= *= /= %= <<= >>= &= |= ^= to new C# programmers they usually say something like “x += 10; is just a short way of writing x = x + 10;”. Now, though that is undoubtedly true for a local variable x of type int, that’s not the whole story, not by far. There are actually many subtle details to the compound assignment operators that you might not appreciate at first glance.
First off, suppose the expression on the left hand side has a side effect or is expensive to call. You only want it to happen once:
class C
{
private int f;
private int P { get; set; }
private static C s = new C();
private static C M()
{
Console.WriteLine("Hello");
return s;
}
private struct Evil
{
public int f; // Mutable value type with a public field, evil!
public int P { get; set; }
}
private static Evil[] evil = new Evil[2000];
private static Evil[] N()
{
Console.WriteLine("Badness");
return evil;
}
If somewhere inside C you have M().f += 10; then you only want M’s side effect to happen once. This is not the same as M().f = M().f + 10;
What is it the same as then? How about this:
C receiver = M();
receiver.f = receiver.f + 10;
Is that right? It seems to be, but suppose we make it a bit more complicated. Suppose we have N()[123].f += 10; . Is this then
Evil receiver = N()[123];
receiver.f = receiver.f + 10;
Clearly not. We've made a copy of the contents of variable N()[123] and we are now mutating the variable containing the copy but we need to be mutating the original.
Once more we see how much pure concentrated evil mutable value types are!
To express the real semantics concisely we need a feature that C# does not have, namely, “ref locals”. C# has ref-typed parameters, but not ref-typed locals. When you make a ref-typed parameter essentially you are saying “this parameter is an alias for this variable”:
void N(ref int x) { x = 10; }
…
N(ref M().f);
Read more: Fabulous Adventures In Coding
0 comments:
Post a Comment