There is a powerful and simple concept in programming that is really underused: Immutability. Basically, an object is immutable if its state doesn’t change once the object has been created. Consequently, a class is immutable if its instances are immutable.
There is one killer argument for using immutable objects: It dramatically simplifies concurrent programming. Think about it, why does writing proper multithreaded programming is a hard task? Because it is hard to synchronize threads accesses to resources (objects or others OS things). Why it is hard to synchronize these accesses? Because it is hard to guarantee that there won’t be race conditions between the multiple write accesses and read accesses done by multiple threads on multiple objects. What if there are no more write accesses? In other words, what if the state of the objects threads are accessing, doesn’t change? There is no more need for synchronization!
Immutable classes are also well adapted to be key in hashtables,The objects on which the hash values are computed must be immutable to make sure that the hash values will be constant in time. Indeed, hash value is computed from the state of the object.
There is one famous immutable class: System.String. When you think that you are modifying a string, you actually create a new string object. Often, we forget about it and we would like to write … String str = ”foofoo”; str.replace(“foo”, “FOO”); …where we need to write instead: str = str.replace(“foo”, ”FOO”); Of course, doing so comes at the cost of creating multiple string objects in memory when doing some intensive string computation. In this case you need to use the StringBuilder class.
The Domain Driven Design is an approach to the design of software, based on the two premises:
In other words the heart of the DDD is Model and the first thing to do when starting development is drawing the model. Model and design you create should shape each other. Model should represent knowledge of the business.
In general the shared data between thread concern the model entities. And making them immutable will eliminate side-effects. I couldn’t say it better than Wes Dyer so I quote him:
“We all know that generally it is not a good idea to use global variables. This is basically the extreme of exposing side-effects (the global scope). Many of the programmers who don’t use global variables don’t realize that the same principles apply to fields, properties, parameters, and variables on a more limited scale: don’t mutate them unless you have a good reason.(…)”
One way to increase the reliability of a unit is to eliminate the side-effects. This makes composing and integrating units together much easier and more robust. Since they are side-effect free, they always work the same no matter the environment. This is called referential transparency.
As we saw, immutability is a feature that can be enforced at compile-time. In other words it can be enforced by static analysis tools. Thus, the Code Query on LINQ feature (CQLinq) that comes with the static analysis tool JArchitect has an IsImmutable condition that applies on types.
To know which types of your code base are immutable it is as easy as writing this CQLinq query:
from t in Types where t.IsImmutable select t
To constraint a particular type MyNamespace. Foo to be immutable you can write this CQLinq constraint:
warnif count != 1
from t in Types where t.IsImmutable && t.FullName==”MyNamespace.Foo”
select t
To constraint a range of types used by the class MyNamespace. Foo to be immutable:
warnif count != 1
from t in Types where t.IsImmutable && t.IsUsedBy(”MyNamespace.Foo”)
select t
We can search for mutable classes derived from a class.
warnif count>0
from t in Types where t.DepthOfDeriveFrom(“Foo.ImmutableClass”)>=0 && ! t.IsImmutable
select t
And also all mutables classes inside a namespace hierarchy.
warnif count>0
from t in Application.Namespaces.WithNameWildcardMatchIn( “Foo.Model”).ChildTypes() where t.DepthOfDeriveFrom(“Foo.ImmutableClass”)>=0 && ! t.IsImmutable
select t
So, what’s behind the IsImmutable CQLinq condition? Here are the rules that JArchitect uses to decide if a type is immutable or not:
Beside the IsImmutable condition on types, we also added 2 conditions on methods: ChangesObjectState and ChangesTypeState.
As the name suggest, ChangesObjectState match methods that are assigning an instance field of its class and the ChangesTypeState match methods that are assigning a static field of its class.
The condition ChangesObjectState matches constructors and static method. The condition ChangesTypeState matches constructors, instance methods and static methods.
These 2 conditions can be used to see at a glance which methods can change the state of your program, in other words, which methods are mutable or non-const, or better said, which methods provoke side-effects.
And as Wes Dier wrote: One way to increase the reliability of a unit is to eliminate the side-effects.
Typically a method that doesn’t provoke side-effects is said to be a pure method. To match pure methods with CQLinq one can write:
from m in Methods
where !m. ChangesObjectState && !m. ChangesTypeState && !m.IsConstructor
select m
Eliminate the side-effects makes composing and integrating units together much easier and more robust, and simplify multithreaded programming.