Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use value and reference types for immutable types? (.NET)

With mutable types, the difference in behaviour between value and reference types is clear:

// Mutable value type
PointMutStruct pms1 = new PointMutStruct(1, 2);
PointMutStruct pms2 = pms1;
// pms1 == (1, 2); pms2 == (1, 2);
pms2.X = 3;
MutateState(pms1); // Changes the X property to 4.
// pms1 == (1, 2); pms2 == (3, 2);

// Mutable reference type
PointMutClass pmc1 = new PointMutClass(1, 2);
PointMutClass pmc2 = pmc1;
// pmc1 == (1, 2); pmc2 == (1, 2);
pmc2.X = 3;
MutateState(pmc1); // Changes the X property to 4.
// pmc1 == (4, 2); pmc2 == (4, 2);

With immutable types however, this difference is less clear cut:

// Immutable value type
PointImmStruct pis1 = new PointImmStruct(1, 2);
PointImmStruct pis2 = pis1;
// pis1 == (1, 2); pis2 == (1, 2);
pis2 = new PointImmStruct(3, pis2.Y);
// Can't mutate pis1
// pis1 == (1, 2); pis2 == (3, 2);

// Immutable reference type
PointImmClass pic1 = new PointImmClass(1, 2);
PointImmClass pic2 = pic1;
// pic1 == (1, 2); pic2 == (1, 2);
pic2 = new PointImmClass(3, pic2.Y);
// Can't mutate pic1 either
// pic1 == (1, 2); pic2 == (3, 2);

Immutable reference types often use value semantics too (e.g. the canonical example System.String):

string s1 = GenerateTestString(); // Generate identical non-interned strings
string s2 = GenerateTestString(); // by dynamically creating them
// object.ReferenceEquals(strA, strB)) == false;
// strA.Equals(strB) == true
// strA == strB

Eric Lippert has discussed before on his blog (e.g. here) that the fact that value types are often (when doesn't really matter for this discussion) allocated on the stack is an implementation detail and that it shouldn't generally dictate whether you make an object a value or reference type.

Given this blurred distinction in behaviour for immutable types, what criteria does this leave for us to decide whether to make an immutable type a reference type or a value type?

Also, with the immutable emphasis on values vs variables, should immutable types always implement value semantics?

like image 675
Mike Lynch Avatar asked May 12 '11 00:05

Mike Lynch


1 Answers

I would say that Eric's blog post you link gives you exactly the answer:

I regret that the documentation does not focus on what is most relevant; by focusing on a largely irrelevant implementation detail, we enlarge the importance of that implementation detail and obscure the importance of what makes a value type semantically useful. I dearly wish that all those articles explaining what “the stack” is would instead spend time explaining what exactly “copied by value” means and how misunderstanding or misusing “copy by value” can cause bugs.

If your objects should have a "copy-by-value" semantic, then make them value types. If they should have a "copy-by-reference" semantic, make them reference types.

He also says this, which I agree with:

I’d always make the choice of value type vs reference type based on whether the type is semantically representing a value or semantically a reference to something.

like image 129
jdmichal Avatar answered Oct 17 '22 05:10

jdmichal