2

When working with mutable structs and properties, it seems strange to me that the compiler can figure some things out, but can't do the same for other rather obvious things.

Take for example the following automatic property:

Vector2 Vector { get; set; }

Instead of typing this:

Vector2 v = Vector;
v += new Vector2(5, 7);
Vector = v;

The compiler is smart enough to let me do this: (Mutability of struct has no effect here)

Vector += new Vector2(5, 7);

But it seems that the compiler isn't smart enough to let me do the following even though I have access to both the setter and the getter -

Vector.X += 4;

Instead I am forced to do this 'manually' -

Vector2 v = Vector;
v.X += 4;
Vector = v;

Is there any particular reason why the compiler team decided to allow the first shorthand form but not the second one?
Aside from the suggested way being obviously more concise, I also imagine that it could potentially allow more efficient inlining for the NGEN/JIT, since it is clear that the copy produced by the getter isn't used anywhere else. (only if this could in some way be reflected in the IL code)

Acidic
  • 6,154
  • 12
  • 46
  • 80
  • 1
    While I can't answer your question directly - why not just add or subtract with a zero's y component? – Vaughan Hilts Aug 07 '12 at 20:46
  • @VaughanHilts that is possible, but what if instead of a `Vector2` it would be a `Vector4`? This just doesn't seem very 'clean' to me: `Vector += new Vector4(4, 0, 0, 0);` – Acidic Aug 07 '12 at 20:49
  • I am assuming `Vector.X += 4;` doesn't work because `Vector` is `null`. Vector is `null` because the compiler makes no assumptions about which vector object you want to point to in the property. – Robert Harvey Aug 07 '12 at 20:50
  • @RobertHarvey `Vector2` is a struct, so it can't be null. – Acidic Aug 07 '12 at 20:54

2 Answers2

2

If Vector2 is a struct (a value type), then assigning to someObject.Vector.X would assign to a temporary copy returned by the Vector property. This never makes sense and is therefore disallowed.

See Why are mutable structs “evil”? for general reference and some links.

Community
  • 1
  • 1
GSerg
  • 76,472
  • 17
  • 159
  • 346
  • `Vector += new Vector2(4, 0)` also seems to be simply mutating a copy, but the compiler team decided to implement it as something else. My question is - why didn't they choose to do the same with my other example. – Acidic Aug 07 '12 at 20:55
  • @Acidic No, that other sample is not mutating a copy, it's mutating the actual value, which is why it's allowed. It's actually meaningful. – Servy Aug 07 '12 at 20:56
  • 2
    @Acidic It is not mutating, it is completely replacing the whole Vector variable, totally overwriting its contents with a new instance. This is very different from assigning just one property of a struct. See the link above. – GSerg Aug 07 '12 at 20:57
  • @Servy @GSerg I wasn't referring to what the compiler actually does, only to what it "looks like". Because `Vector.X += 4` doesn't compile at all, this answer can only reflect on how this piece of code might look like, now to how it actually compiles. (since it doesn't) – Acidic Aug 07 '12 at 21:00
  • @Acidic It looks like changing one of the properties of some object, but in fact it does not happen. This is why this is spotted by compiler as an error. It could let you do it and compile it just fine, but then you'd keep wondering why your `Vector.X` didn't actually change. See [Mark Gravell's answer](http://stackoverflow.com/a/441323/11683) and the [linked article](http://blogs.msdn.com/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx). – GSerg Aug 07 '12 at 21:04
  • My point is that it *should* do something, and that would be: 1) use the getter to get a copy of the struct. 2) mutate the copy. 3) send the copy to the setter. This WOULD actually do something. It is up to the compiler to decide if this does anything or not, and I simply don't understand why it doesn't. – Acidic Aug 07 '12 at 21:08
  • @Acidic Then the difference between value semantics and reference semantics would disappear. At which point we get the C++ language. The C# creators decided it would be nice to let the programmer decide when to use the value semantics and when to use the reference semantics. What you are doing is using the value semantics and complaining it does not behave as the reference semantics. – GSerg Aug 07 '12 at 21:10
  • That is entirely not what value semantics are about. This particular case is simply introducing a shorthand form of writing the same code - and with added readability. – Acidic Aug 07 '12 at 21:11
2

It's not a matter of the compiler being smart enough, it's a matter of what the code compiles to.

Vector += new Vector2(5, 7);

compiles to

Vector = Vector + new vector2(5,7);

so we have an assignment. All fine.

Vector.X += 2;

Compiles to

var v = Vector;
v.X = v.X + 2

No assignment back to Vector.

Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
  • Vector.X += 2 actually doesn't compile at all at the moment. – Acidic Aug 07 '12 at 20:50
  • @Acidic Read as "translates to." – GSerg Aug 07 '12 at 20:51
  • 1
    The compiler is smart enough to know that this will never do anything (productive), and so there is a specific error (or warning?) just for this because the programmer almost certainly made a mistake if they did this. – Servy Aug 07 '12 at 20:57
  • The compiler simply knows that this is disallowed. On the same note the compiler team could have also chosen to not allow the use of `+=` with properties, because that also *"might look like"* it mutates a copy, instead of actually sending a value through the setter. – Acidic Aug 07 '12 at 21:02