The “Structs Should Always be Immutable” Guideline
Sometimes one comes across the following guideline for C# structs:
All structs should be immutable.
The results of searching the web for justification for this are not very satisfying.
One argument sometimes advanced is that an immutable struct is usually simpler to understand than a mutable struct. This argument is true, but it also applies to classes, so it doesn’t explain why mutable classes should exist. Obviously we need mutable classes if the language is to be very useful as an object oriented language, so the simplicity argument for immutable structs has a major weakness.
A second argument is that making all structs immutable simplifies multithreaded applications, because it allows client code to be written without having to do the copying that is necessary with mutable structs:
void threadSafeMethod(mutableStruct s)
{
mutableStruct t = s;
(work with t)
}
This argument, too, is useful to know, and this argument, too, applies to classes and so is not a satisfying justification for why structs should be immutable.
A third argument for making structs immutable is that prominent value types are immutable, and many people will reason by analogy that structs should behave like the prominent exemplars of value types such as Int64 and Double. A struct that behaves differently would violate this expectation. This argument does not apply to classes and so may be somewhat more satisfying than the first two arguments.
A fourth argument for making structs immutable is to make it impossible to have a certain weird scenario where a boxed instance can be modified. This scenario violates reasonable client assumptions that values residing inside a box will not be modified. It is a satisfying argument because it does not apply to classes, since class instances cannot be boxed.
The weird scenario for modifying boxed values is described in Richter’s book, CLR via C#, Microsoft Press, 2006. Below is an adaptation.
using System;
interface IChangeable
{ void Change(int v); }
struct S : IChangeable
{
int _v;
public S(int v)
{ _v = v; }
public void Change(int v)
{ _v = v; }
public override string ToString()
{ return _v.ToString(); }
}
public class BoxingExample
{
static void Main()
{
S s = new S(3);
Object boxed = s;
// One might expect the value in 'boxed'
// to always be 3 after this point.
((IChangeable) boxed).Change(4);
// But the next line prints "4"!!
Console.WriteLine("boxed={0}", boxed);
}
}
Posted on February 19th, 2007 by Andrew
Under C# / Common Language Infrastructure
Leave a Reply
You must be logged in to post a comment.