Last week, we are changing the architecture of a project a bit. Some functions returned string messages. Well string messages from all sorts of classes defined in a constant namespace.
I was assigned the job to clean that mess up and have a single class that contained codes for all possible messages. Each function would now return some message code which would latter be looked up through another function. That function was interface specific as there were a number of ways to call those core function. Each interface necessitated its own handling of message codes.
So far so good, I unified the message codes, removed a couple of classes whose sole purpose was to act as a container to some weird error condition. All messages ended up in one class and there corresponding codes in another. Everything was working fine till that moment.
During that entire process, I had to go through almost all the code which made me quite sentimental about the project as it had been written over the past two years by people I never heard of. You could almost associate a personality to a piece of code by simply looking at it.
This had many revelations for me. Unnecessary lines, improperly written loops, things like
bool flag = true;
if( flag )
The thing I wrote above is very neatly formatted, image this with no indentation and multiple statements on one line.
Since every thing was done successfully and the application worked correctly, apart from two or three codes left from the final lookup function, my spirits were really high. And having seen almost all code written over a long period of time, I noticed some functions took there parameters by reference. Running FxCop identified them as design changes. I went ahead and removed ref from every type which was not a valuetype. But alas, I forgot the check after this breaking change that the application was still working fine or not.
Many use cases were broken. You see the problem was that I removed ref from string parameters too, which were being modified in the function and the caller needed that modified value. You may wonder why string needed that special handling, it is because a string once created, is immutable. Any time you change it to something else, it creates a new string with the new contents and old copy is unmodified.
Here is a little program to demonstrate that. You should see the message You have been bitten in the butt. printed on the command line. [Note: If you also see Even this does not work, you should check you compiler’s sanity.]
public class Program
public static void Main( )
string message = "Message";
BiteInTheButt( message );
if ( message != "New message" )
Console.WriteLine( "You have been bitten in the butt." );
BiteInTheButt( ref message );
if ( message != "New message 2" )
Console.WriteLine( "Even this does not work" );
static void BiteInTheButt( string message )
message = "New message";
static void BiteInTheButt( ref string message )
message = "New message 2";
This problem will happen with any immutable type. If you want to modify the original object passed in argument, you should pass it as ref parameter. I also suppose the Freezables in WPF behave similarly after they are frozen, no matter what you do with them in the caller, there is simply no way to propagate back the changes you do.
In general, if you pass an immutable type as argument and want any changes made to it to be propagated back, prefix it with a ref!