Code Analysis: Shared Mutable State

May 16, 2017

My previous post asserts that mutable state can cause a software engineer issues in understanding the program because it becomes arbitrarily hard to understand when two different parts of a program are actually connected.  This is also why some sort of run time debugging facility is needed in order to understand some types of code.

Things were looking kind of bad, but they can actually get worse.  Let’s take a look at a program where there are mutable references that are shared by multiple entities.

Given some reference “B” and some reference “A”, does the box on the right depend on the box on the left?  What do we have to do in order to get the answer?

First off we have to jump through all the hoops that exist for contexts that involve mutable references.  But things get a little bit more involved because:

class A {     public bool X; } class B {     public A Value; } B MakeB( A a ) {     if ( some_condition )         return new B( a );     else         return new B( new A() ); } void Main() {     var a = new A();     var b = MakeB( a );     FunctionChainThatMaybeChangesAInB( b );    ImportantFunctionThatDependsOnA( a ); }

We also have to consider what happens to “B”.  At the very least with the plain old mutable reference use case, you can look at all the places where “A” is being used and that gets you a starting point.  But once you have shared mutable references, you also have to consider any reference that also holds your other reference.  Additionally, consider the MakeB function above.  This function conditionally uses the “A” reference.

Shared mutable references are problematic because you need a debugger and knowledge of, potentially, the entire code base.

Like I said earlier, this doesn’t make mutable state (even if you can share it) bad.  It just means that an undisciplined use of mutable state can make understanding the code base a very involved and difficult problem.

Let’s take a closer look at these diagrams.