This series on immutable types has turned into something of an epic - when I began, I never expected it to become a series of this length. For now, the final question I want to address is a simple one: Why are immutable types important?
I suggest there are several reasons why you should consider using immutable types in your code, and why you should think about creating your own immutable types.
Immutability means ease of reasoning
The state of an immutable type is fixed at creation. All of the functionality of such a type need only be understood and reasoned about with respect to the initial state of the class. With mutable types, all of the members need to behave properly regardless of how the internal state changes. I know I’ve found and fixed any number of bugs in mutable classes that have arisen when new possible states are introduced.
Immutability eases concurency
While nothing can make concurrent code actually easy to write, immutable types make things a lot simpler by trivially supporting concurrent read access. Explicit control of concurrent access is only required for write access - and given that this almost always boils down to replacing one value with another, those locks tend to be very short.
Immutability reduces memory load
The nature of pervasive (and safe) sharing of information between immutable instances works to reduce the amount of memory required. Instead of needing to make independent copies of data to ensure fast and safe concurrent access, immutable instances can immediately be shared and (re)used. A reference copy, allowing for comparison or easy reversal of changes, also requires no copying.
Immutability can improve performance
Without the need for explicit copying, parallel algorithms can run much faster; in some cases, the reuse of shared data allows all of the data to be kept in processor caches, for an additional performance improvement. It’s also possible for immutable types to cache results more effectively (e.g. no need to recalculate a hash code after the first time when instance never changes), allowing more reuse of calculated results.
If you’ve enjoyed this series, here are some ideas on what to do next.
Keep experimenting with immutable types, especially with writing your own. If you identify a semantic type (such as a time series id or a certificate thumbprint), try writing your own implementation as an immutable type.
Read more about immutable types. If you have an academic mindset, you might enjoy reading Purely Functional Data Types by Chris Okasaki. Written in 1998, it’s still a key reference in the field. Fair warning, though - this one will turn the brain of any ordinary mortal into a pretzel.
Try out the immutable classes found in the System.Collections.Immutable NuGet package. Usefully, the full source is available as a part of .Net core. I’ve found the ImmutableHashSet class to be particularly useful.
For now, that’s the end of this series. I hope you’ve enjoyed it.