Reference Semantics and Code Readability

One of the features Microsoft packed with C# 7.2 is Reference Semantics with Value Types. Though designed with the intention to improve performance by eliminating the need for copying (and thereby allocating memory) value types , I do have my reservations on the complexity it adds to readability of code for a programmer. Let’s consider the case of “in” keyword.

 

The “in” allows the programmer to pass a parameter by reference, but on the condition that the method cannot modifying the value.  For example
void IncrementAndPrint(in int Counter)
{
    Counter++;   // this will throw error.
    Console.WriteLine(Counter);
}

void Print(in int Counter)
{
    Console.WriteLine(Counter);
}

We could delve into details of “in” on a later post, however, for this post, we will focus on the readability factor. One of the features of “in”, which separates it out from “ref” and “out” is that, you don’t necessarily (yeah…keyword is optional during invocation) use the keyword before using it. For example, for the above method Print , both following method invocation is valid.

int counterValue = 3;
Print(in counterValue);
Print(counterValue);

However, the framework restricts you from passing an expression or direct value with the “in” parameter. This restriction is not valid if you are not using the optional “in” keyword.

Print(in 3); // Invalid code
Print(3);      // This is valid.

Another scenario worth consideration is when there is an overloaded method of Print which doesn’t use the pass by reference. Consider the following two overloaded methods.

void Print(in int Counter)
{
     Console.WriteLine($"Pass By Reference :{Counter}");
}
void Print(int Counter)
{
     Console.WriteLine($"Pass By Value :{Counter}");
}

Understandably, the first method uses “in” keyword to pass the parameter by reference, while the second passes the parameter by value. Considering the “in” parameter is optional, what would be the output of following method invocations.

int num = 3;
Print(in num);
Print(num);

Output

Pass By Reference : 3
Pass By Value : 3

It is on expected lines as Microsoft would have wanted, however, the question is, does the ability of “optional in” do justice to readability of code ?

Code Smells : Change Preventers

If you ever have been in a situation when you need to make change in one place, but had to make changes in many places too, then Change Preventers is a code smell you should be vary off. Change Preventers is result of poor structuring of code and can be broadly categorized into 3.

Divergent Change

Symptoms of Divergent Change are obvious when you have to make changes in several unrelated methods when you need to make a single change in a class. The solution for the code smell lies in splitting up the class. We could segregate the different behaviors of the class using Extract Class or in scenarios where, different classes have same behavior, we could employ Extract SubClass or Extract SuperClass whichever seem appropriate for the particular scenario.

Shotgun Surgery

Another closely related Change Preventer is known as Shotgun Surgery, which is almost opposite to Divergent Change. With Divergent Change, many changes were required to a Single Class, while with Shotgun Surgery, a single change is made to several classes. This is a resultant of a single responsibility split among many classes and can happen due to ‘over-refactoring’.

The resolution lies in bringing together all associated methods to form a single class that has the responsibility rather than distributing it over multiple classes. Refactoring techniques like Move Method and Move Field can be employed for the purpose.

Parrallel Inheritance Hierarchy

If you find your self in situations where you intend to create a derived class, but also end up having to create sub classes for another class, then Parallel Inheritance Hierarchy. This eventually would result in making changes harder as related changes would be spread across the codebase.

To remove such duplication, we would need to employ refactoring techniques like Move Method and Move Field after creating a reference of the dependent class in your original class. Once all the methods and fields has been moved, you can get rid of the reference and duplicate class.

Switching Context With Async

Whenever an await is encountered in the code, a context is captured, which is later used when the promise is completed and ready to continue. If the method is called by the UI thread, usually, the context could be UI context, unless the awaited method itself creates a new thread. This can be demonstrated in the following example.

 

async Task DoAsync()
{
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    await Task.Delay(TimeSpan.FromSeconds(3));
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);

}
The ThreadID displayed would be the same. However, there could be scenarios where you might be interested to actually switch the context. The framework provides an easy way to do same, using the ConfigureAwait method, which accepts a boolean which dictates whether to continue on captured context. Let’s change the above code and check the new output.

 

async Task DoAsync()
{
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);

}
The ThreadIDs would be different in this case.

Stephen Clearly mentions a deadlock situation in his famous book, where ConfigureAwait helps in breaking the deadlock. Let’s consider the deadlock situation first.

private async void button1_Click(object sender, EventArgs e)
{
Task temp = DoAsync();
Debug.WriteLine("Continue");
temp.Wait();
Debug.WriteLine("Not Deadlock");
}

async Task DoAsync()
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(TimeSpan.FromSeconds(3));
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);

}

The above code would end up in a deadlock. This is because, in the DoAsync Method, the captured context in which the execution needs to continue, has a thread which is already blocked by the Wait Method in the calling Button_Click event. Since the context only allows a single thread to continue, this would result in a deadlock situation. This could be resolved if we switch context in the await method.

Multicasting with Action

Func and Action are inherited from System.MulticastDelegate, which means that you could actually do multicasting with them and add multiple methods to the InvocationList. Let’s check how we do it.

Action Action1 = () => Console.WriteLine($"Hello From {nameof(Action1)}");
Action Action2 = () => Console.WriteLine($"Hello From {nameof(Action2)}");
Action Action3 = () => Console.WriteLine($"Hello From {nameof(Action3)}");
Action Action4 = () => Console.WriteLine($"Hello From {nameof(Action4)}");
Action Actions = Action1 + Action2 + Action3 + Action4;
Console.WriteLine($"Length of Invocation List :  {Actions.GetInvocationList().GetLength(0)}");
Actions();

Output of above code would be

Hello From Action1
Hello From Action2
Hello From Action3
Hello From Action4

The same can be done with Func as well. How do we remove one Action , same syntax as the delegates.

Actions -= Action4;

In fact, we could also use Actions instead of specifying delegates for events.

void Main()
{
  var demo = new DemoClass();
  demo.OutOfRange += ()=> Console.WriteLine("Out of Range");
  demo.NotAllowed += (x)=> Console.WriteLine($"Not Allowed : {x}");
  demo.Method1();
}
public class DemoClass
{
public event Action OutOfRange;
public event Action NotAllowed;
public void Method1()
{
       if(OutOfRange != null)
       OutOfRange();

       if(NotAllowed !=null)
       NotAllowed("Hey that's not allowed");
}
}
We could tweak it further by assigning a default action for our events. In this way, you can remove the checks for null. This is a possibility, but I am not quite sure if Microsoft Coding Conventions recommend Actions for events.

Regular Expression – Compiled vs Interpreted

Regular Expression gives the developer a clean and efficient method to parse strings. However, it comes at a cost – there is a inherent performance hit associated with regular expressions, especially if you are running some kind of long loops and parsing the string inside it. One way to tackle it is using compiled regular expressions, which .Net provides by using the RegexOptions.Compiled property. Let’s examine the performance of the Interpreted version of regular expression and the compiled version in a long loop.

We will consider a simple regular expression that is intended to parse a valid date.

void Main()
{
	string regex = @"^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}$";
	var countArray = new int[]{100,1_000,10_000,1_00_000,10_00_000, Int32.MaxValue};
	foreach(var count in countArray)
	{
		RunLoop(regex,count,false);
		RunLoop(regex,count,true);
	}
}

void RunLoop(string regexStr,int maxCount,bool isCompiled)
{
	Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < maxCount; i++)
    {
		if(isCompiled)
        	Regex.IsMatch("23/2/2018", regexStr,RegexOptions.Compiled);
		else
			Regex.IsMatch("23/2/2018", regexStr);
				
	}

    watch.Stop();
    Console.WriteLine($"Time Ellapsed : {watch.Elapsed.Minutes}:{watch.Elapsed.Seconds}:{watch.Elapsed.Milliseconds}");
            
}

I ran the above code on different values for maxCount. You can view the comparison of Compiled Version Vs Interpreted Version below.

Iterations
Interpreted
Compiled
Int.MaxValue
26:13:629
15:44:589
10,00,000
00:00:793
00:00:450
1,00,000
00:00:79
00:00:57
10,000
00:00:09
00:00:07
1,000
00:00:01
00:00:02
100
00:00:00
00:00:02
As you can see, the more you need to use the same regular expression, Compiled Version is better. However, if the usage is very less, the compiler version turns expensive.