0
votes

According to Wikipedia's article on value objects, C# value objects are both immutable and copied attribute-wise.

If they're immutable, why make copies? Even if it helps memory locality, is that general enough of an optimization to make it the default behavior?

Edit: Oh, I think I misunderstood immutability.

So does immutability mean you can't modify the attributes individually, but you can replace the entire internals from an existing object? But doesn't that violate "if two things are equal, they will always be equal"?

3
I think that article is just badly worded. It's trying to say the opposite of what it appears to say. - David Schwartz
Value types do not have to be immutable. It is recommended but not necessary. System.Drawing.Rectangle is not immutable. - clcto
@DavidSchwartz That article is terrible; among other things is includes the usual "struct is kept in the stack while classes are stored in the heap" nonsense. - Michael Edenfield

3 Answers

0
votes

So does immutability mean you can't modify the attributes individually, but you can replace the entire internals from an existing object?

Yes.

But doesn't that violate "if two things are equal, they will always be equal"?

No. Why would it? If you replace the internals from an existing object, you get a new object with different internals.

0
votes

I'm not agreeing with the given claims, but I'll attempt to explain what I believe they intend to say.

The fact that structure types are immutable means that

public struct S { int i; }
public S f() { /* omitted */ }
public void g() { f().i = 3; }

is a compile-time error: it wouldn't make sense to modify f()'s result, because the modification would be immediately lost.

In contrast,

public struct S { int i; }
public S f() { /* omitted */ }
public void g() { var s = f(); s.i = 3; }

is fine, but s.i = 3; can be interpreted as rewriting all of s: it can be interpreted as equivalent to (pseudo-code) s = { 3 };, where { 3 } constructs a whole new S value object.

But doesn't that violate "if two things are equal, they will always be equal"?

By their interpretation, this is still true. After s.i = 3;, s is a whole new value. Before the assignment to s.i, s was equal to f()'s result. After the assignment to s.i, s itself fundamentally changes, and it's not just a modification of a property of that object, you've got a whole new object, which was never equal to any other object except perhaps by chance.

Their interpretation is consistent with how C# actually works, although their phrasing is not how I usually see it, or how I would put it. Beware that other documentation may make different claims that at first glance will seem to totally contradict these.

0
votes

Everything is copied by value unless you use the ref keyword. The difference between value types and reference types is:

  • variables/fields whose type is a value-type are allocated where they are declared. This can be the current stack frame if they are local method variables. But it can also be the heap if they are part of an object already on the heap.
  • variables/fields whose type is a reference-type contain a reference to an object that is allocated on the heap.

Since value-types are allocated "in-place" when you assign a variable to another, your're actually copying the object's members. When you assign a reference-type variable to another you're copying the reference to the same object on the heap. Either way, you're always copying the content of the variable.