What Are The Benefits of an Immutable Struct Over a Mutable One

What are the benefits of an immutable struct over a mutable one?

Different approaches will facilitate different kinds of changes to the code. An immutable structure is very similar to an immutable class object, but a mutable structure and a mutable class object are very different. Thus, code which uses an immutable structure can often be readily adapted if for some reason it becomes necessary to use a class object instead.

On the flip side, use of an immutable object will often make the code to replace a variable with a modified version more brittle in case additional properties are added to the type in question. For example, if a PhoneNumber type includes methods for AreaCode, LocalExchange, and LocalNumber and a constructor that takes those parameters, and then adds an "optional" fourth property for Extension, then code which is supposed to change the area codes of certain phone numbers by passing the new area code, LocalExchange, and LocalNumber, to the three-argument constructor will erase the Extension property of every phone number, while code which could write to AreaCode directly wouldn't have had that problem.

Immutable class vs struct

Since copying reference is cheaper than copying struct, why would one use an immutable struct?

This isn't always true. Copying a reference is going to be 8 bytes on a 64bit OS, which is potentially larger than many structs.

Also note that creation of the class is likely more expensive. Creating a struct is often done completely on the stack (though there are many exceptions), which is very fast. Creating a class requires creating the object handle (for the garbage collector), creating the reference on the stack, and tracking the object's lifetime. This can add GC pressure, which also has a real cost.

That being said, creating a large immutable struct is likely not a good idea, which is part of why the Guidelines for choosing between Classes and Structures recommend always using a class if your struct will be more than 16 bytes, if it will be boxed, and other issues that make the difference smaller.

That being said, I often base my decision more on the intended usage and meaning of the type in question. Value types should be used to refer to a single value (again, refer to guidelines), and often have a semantic meaning and expected usage different than classes. This is often just as important as the performance characteristics when making the choice between class or struct.

Why is it okay that this struct is mutable? When are mutable structs acceptable?

Actually, if you search for all classes containing BitVector in the .NET framework, you'll find a bunch of these beasts :-)

  • System.Collections.Specialized.BitVector32 (the sole public one...)
  • System.Web.Util.SafeBitVector32 (thread safe)
  • System.Web.Util.SimpleBitVector32
  • System.Runtime.Caching.SafeBitVector32 (thread safe)
  • System.Configuration.SafeBitVector32 (thread safe)
  • System.Configuration.SimpleBitVector32

And if you look here were resides the SSCLI (Microsoft Shared Source CLI, aka ROTOR) source of System.Configuration.SimpleBitVector32, you'll find this comment:

//
// This is a cut down copy of System.Collections.Specialized.BitVector32. The
// reason this is here is because it is used rather intensively by Control and
// WebControl. As a result, being able to inline this operations results in a
// measurable performance gain, at the expense of some maintainability.
//
[Serializable()]
internal struct SimpleBitVector32

I believe this says it all. I think the System.Web.Util one is more elaborate but built on the same grounds.

Why are mutable structs “evil”?

Structs are value types which means they are copied when they are passed around.

So if you change a copy you are changing only that copy, not the original and not any other copies which might be around.

If your struct is immutable then all automatic copies resulting from being passed by value will be the same.

If you want to change it you have to consciously do it by creating a new instance of the struct with the modified data. (not a copy)

Why are C# structs immutable?

If this subject interests you, I have a number of articles about immutable programming at https://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/

I was just curious to know why structs, strings etc are immutable?

Structs and classes are not immutable by default, though it is a best practice to make structs immutable. I like immutable classes too.

Strings are immutable.

What is the reason for making them immutable and rest of the objects as mutable.

Reasons to make all types immutable:

  • It is easier to reason about objects that do not change. If I have a queue with three items in it, I know it is not empty now, it was not empty five minutes ago, it will not be empty in the future. It's immutable! Once I know a fact about it, I can use that fact forever. Facts about immutable objects do not go stale.

  • A special case of the first point: immutable objects are much easier to make threadsafe. Most thread safety problems are due to writes on one thread and reads on another; immutable objects don't have writes.

  • Immutable objects can be taken apart and re-used. For example, if you have an immutable binary tree then you can use its left and right subtrees as subtrees of a different tree without worrying about it. In a mutable structure you typically end up making copies of data to re-use it because you don't want changes to one logical object affecting another. This can save lots of time and memory.

Reasons to make structs immutable

There are lots of reasons to make structs immutable. Here's just one.

Structs are copied by value, not by reference. It is easy to accidentally treat a struct as being copied by reference. For example:

void M()
{
S s = whatever;
... lots of code ...
s.Mutate();
... lots more code ...
Console.WriteLine(s.Foo);
...
}

Now you want to refactor some of that code into a helper method:

void Helper(S s)
{
... lots of code ...
s.Mutate();
... lots more code ...
}

WRONG! That should be (ref S s) -- if you don't do that then the mutation will happen on a copy of s. If you don't allow mutations in the first place then all these sorts of problems go away.

Reasons to make strings immutable

Remember my first point about facts about immutable structures staying facts?

Suppose string were mutable:

public static File OpenFile(string filename)
{
if (!HasPermission(filename)) throw new SecurityException();
return InternalOpenFile(filename);
}

What if the hostile caller mutates filename after the security check and before the file is opened? The code just opened a file that they might not have permission to!

Again, mutable data is hard to reason about. You want the fact "this caller is authorized to see the file described by this string" to be true forever, not until a mutation happens. With mutable strings, to write secure code we'd constantly have to be making copies of data that we know do not change.

What are the things that are considered to make an object immutable?

Does the type logically represent something that is an "eternal" value? The number 12 is the number 12; it doesn't change. Integers should be immutable. The point (10, 30) is the point (10, 30); it doesn't change. Points should be immutable. The string "abc" is the string "abc"; it doesn't change. Strings should be immutable. The list (10, 20, 30) doesn't change. And so on.

Sometimes the type represents things that do change. Mary Smith's last name is Smith, but tomorrow she might be Mary Jones. Or Miss Smith today might be Doctor Smith tomorrow. The alien has fifty health points now but has ten after being hit by the laser beam. Some things are best represented as mutations.

Is there any difference on the way how memory is allocated and deallocated for mutable and immutable objects?

Not as such. As I mentioned before though, one of the nice things about immutable values is that something you can re-use parts of them without making copies. So in that sense, memory allocation can be very different.

Mutable vs immutable objects

Well, there are a few aspects to this.

  1. Mutable objects without reference-identity can cause bugs at odd times. For example, consider a Person bean with a value-based equals method:

    Map<Person, String> map = ...
    Person p = new Person();
    map.put(p, "Hey, there!");

    p.setName("Daniel");
    map.get(p); // => null

    The Person instance gets "lost" in the map when used as a key because its hashCode and equality were based upon mutable values. Those values changed outside the map and all of the hashing became obsolete. Theorists like to harp on this point, but in practice I haven't found it to be too much of an issue.

  2. Another aspect is the logical "reasonability" of your code. This is a hard term to define, encompassing everything from readability to flow. Generically, you should be able to look at a piece of code and easily understand what it does. But more important than that, you should be able to convince yourself that it does what it does correctly. When objects can change independently across different code "domains", it sometimes becomes difficult to keep track of what is where and why ("spooky action at a distance"). This is a more difficult concept to exemplify, but it's something that is often faced in larger, more complex architectures.

  3. Finally, mutable objects are killer in concurrent situations. Whenever you access a mutable object from separate threads, you have to deal with locking. This reduces throughput and makes your code dramatically more difficult to maintain. A sufficiently complicated system blows this problem so far out of proportion that it becomes nearly impossible to maintain (even for concurrency experts).

Immutable objects (and more particularly, immutable collections) avoid all of these problems. Once you get your mind around how they work, your code will develop into something which is easier to read, easier to maintain and less likely to fail in odd and unpredictable ways. Immutable objects are even easier to test, due not only to their easy mockability, but also the code patterns they tend to enforce. In short, they're good practice all around!

With that said, I'm hardly a zealot in this matter. Some problems just don't model nicely when everything is immutable. But I do think that you should try to push as much of your code in that direction as possible, assuming of course that you're using a language which makes this a tenable opinion (C/C++ makes this very difficult, as does Java). In short: the advantages depend somewhat on your problem, but I would tend to prefer immutability.

Pros. / Cons. of Immutability vs. Mutability

Many functional languages are non pure (allow mutation and side effects).

f# is for example, and if you look at some of the very low level constructs in the collections you'll find that several use iteration under the hood and quite a few use some mutable state (if you want to take the first n elements of a sequence it's so much easier to have a counter for example).

The trick is that this is something to generally:

  1. Use sparingly
  2. Draw attention to when you do

    • note how in f# you must declare something to be mutable

That it is possible to largely avoid mutating state is evidenced by the large amount of functional code out there. For people brought up on imperative languages this is somewhat hard to get your head round, especially writing code previously in loops as recursive functions. Even trickier is then writing them, where possible, as tail recursive. Knowing how to do this is beneficial and can lead to far more expressive solutions that focus on the logic rather than the implementation. Good examples are those that deal with collections where the 'base cases' of having no, one or many elements are cleanly expressed rather than being part of the loop logic.

It is really 2 though that things are better. And this is best done via an example:

Take your code base and change every instance variable to readonly[1][2]. Change back only those ones where you need them to be mutable for your code to function (if you only set them once outside the constructor consider trying to make them arguments to the constructor rather than mutable via something like a property.

There are some code bases this will not work well with, gui/widget heavy code and some libraries (notably mutable collections) for example but I would say that most reasonable code will allow over 50% of all instance fields to be made readonly.

At this point you must ask yourself, "why is mutable the default?".
Mutable fields are in fact a complex aspect of your program as their interactions, even in a single threaded world, have far more scope for differing behaviour; as such they are best highlighted and drawn to the attention of the coder rather than left 'naked' to the ravages of the world.

It is notable that most functional languages have either no concept of null or make it very hard to use because they work, not with variables, but with named values whose value is defined at the same time (well scope) the name is.


  1. I find it unfortunate that c# did not copy java's concept of immutability with local variables too. Being able to assert emphatically that something doesn't change helps make intent clear whether a value is on the stack or in an object/struct.

  2. If you have NDepend then you can find these with WARN IF Count > 0 IN SELECT FIELDS WHERE IsImmutable AND !IsInitOnly

What about a mutable struct that's immutable from the standpoint of external code?

There's nothing wrong with having immutable data structures that internally use mutation (so long as the thread safety is well advertised). It's just that structs get copied all the time, so you can't do much with mutation. This isn't a problem in C/C++ because structs are usually passed by reference, whereas in C# it is rare to pass structs by reference. Since it's hard to reason about structs that are passed by value, mutable structs are discouraged in C#.

C# Structs: Mutability versus Performance

There are two distinct usage cases for structs; in some cases, one wants a type that encapsulates a single value and behaves mostly like a class, but with better performance and a non-null default value. In such cases, one should use what I would call an opaque structure; MSDN's guidelines for structures are written on the assumption that this is the only usage case.

In other cases, however, the purpose of the struct is simply to bind some variables together with duct tape. In those cases, one should use a transparent struct which simply exposes those variables as public fields. There is nothing evil about such types. What's evil is the notion that everything should behave like a class object, or that everything should be "encapsulated". If the semantics of the struct are such that:

  1. There is some fixed set of readable members (fields or properties) which expose its entire state
  2. Given any set of desired values for those members, one can create an instance with those values (no combinations of values are forbidden).
  3. The default value of the struct should be to have all those members set to the default values of their respective types.

and any change to them would break the code which uses it, then there is nothing which future versions of the struct could possibly do which a transparent struct would not be able to do, nor is there anything that a transparent struct would allow which a future version of the struct would be able to prevent. Consequently, encapsulation imposes cost without adding value.

I would suggest that one should endeavor to, whenever practical, make all structs either transparent or opaque. Further, I would suggest that because of deficiencies in the way .net handles struct methods, one should avoid having opaque structures' public members modify this except perhaps in property setters. It is ironic that while MSDN's guidelines suggest one shouldn't use a struct for things that don't represent a "single value", in the common scenario where one simply wants to pass a group of variables from one piece of code to another, transparent structs are vastly superior to opaque structs or class types, and the margin of superiority grows with the number of fields.

BTW, with regard to the original question, I would suggest that it's useful to represent that your program may want to deal with two kinds of things: (1) a car, and (2) information related to a particular car. I would suggest that it may be helpful to have a struct CarState, and have instances of Car hold a field of type CarState. This would allow instances of Car to expose their state to outside code and possibly allow outside code to modify their state under controlled circumstances (using methods like

delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, T3 p3);

void UpdateState<TP1>(ActionByRef<CarState, TP1> proc, ref TP1 p1)
{ proc(ref myState, ref p1); }
void UpdateState<TP1,TP2>(ActionByRef<CarState, TP1,TP2> proc, ref TP1 p1, ref TP2 p2)
{ proc(ref myState, ref p1, ref p2); }

Note that such methods offer most of the performance advantages of having the car's state be a mutable class, but without the dangers associated with promiscuous object references. A Car can let outside code may update a car's state via the above methods without allowing outside code to modify its state at any other time.

BTW, I really wish .net had a way of specifying that a "safe" struct or class should be considered as encapsulating the members of one or more of its constituents [e.g. so that struct which held a Rectangle called R and an String called Name could be regarded as having a fields X, Y, Width, and Height which alias the corresponding struct fields. If that were possible, it would greatly facilitate situations where a type needs to hold more state than previously expected. I don't think the present CIL allows for such aliasing in a safe type, but there's no conceptual reason it couldn't.

Choosing between immutable objects and structs for value objects

How do you choose between implementing a value object (the canonical example being an address) as an immutable object or a struct?

I think your options are wrong. Immutable object and struct are not opposites, nor are they the only options. Rather, you've got four options:

  • Class

    • mutable
    • immutable
  • Struct

    • mutable
    • immutable

I argue that in .NET, the default choice should be a mutable class to represent logic and an immutable class to represent an entity. I actually tend to choose immutable classes even for logic implementations, if at all feasible. Structs should be reserved for small types that emulate value semantics, e.g. a custom Date type, a Complex number type similar entities. The emphasis here is on small since you don't want to copy large blobs of data, and indirection through references is actually cheap (so we don't gain much by using structs). I tend to make structs always immutable (I can't think of a single exception at the moment). Since this best fits the semantics of the intrinsic value types I find it a good rule to follow.



Related Topics



Leave a reply



Submit