Thursday 17 September 2020

struct and interface : The confusion

The fact that, in C#, a value type like struct can implement an interface can be perplexing. It can lead to few misunderstanding unless you stick to one basic fact that struct is a value type. 

Let us create an interface for example.

public interface ITemp

{

        void M();

}

As it is allowed, we can have a struct that implements this interface.

public struct Temp2 : ITemp

{

        private int val;

        public void M()

        {

            val++;

            Console.WriteLine(val);

        }

}

So far, so good.

What happens if i pass a structure to a method that accepts parameter of type ITemp? Magic of boxing/unboxing takes place that ensures that struct is being passed as a reference. If you have a method that takes parameter of type struct Temp2, the value will be passed as value.

private static void Run(Temp2 temp)

{

            temp.M();

}

private static void Run2(ITemp temp)

{

            temp.M();

}

static void Main(string[] args)

{

var tempStruct = new Temp2();

tempStruct.M(); 

Run(tempStruct);

tempStruct.M();

Run2(tempStruct);

}

As you would have guessed, here is the output.

1

2

2

3

Hopefully, this clarifies the behavior of struct types that implement an interface.

Saturday 12 September 2020

The cost of function call stacks

 So, this one is pretty much a known thing but is generally overlooked. There is a cost associated with each function call stack and as an application developer, we should try to find ways to avoid unnecessary calls.

Let us take a look at an example. I have written 2 versions of a Fibonacci series function in C#.

static void Main(string[] args)
        {
            int number = 42;
            Program p = new Program();
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Console.WriteLine(p.Fibonacci(number));
            sw.Stop();
            Console.WriteLine($"Time taken in ms : {sw.ElapsedMilliseconds}");
           sw.Restart();
            Console.WriteLine(p.FibonacciV2(number));
            sw.Stop();
            Console.WriteLine($"Time taken in ms : {sw.ElapsedMilliseconds}");
        }

        public int Fibonacci(int n)
        {
            if(n == 0 || n == 1){
                return n;
            }

            return Fibonacci(n-2) + Fibonacci(n-1);
        }

        public int FibonacciV2(int n)
        {
            if(n == 0 || n == 1){
                return n;
            }
            
            int result = 0;
            Dictionary<intinttemp = new Dictionary<intint>();
            temp.Add(00);
            temp.Add(11);
            for(int i = 2i <= ni++){
                result = temp[i-2] + temp[i-1];
                temp[i] = result;
            }

            return result;
        }

I compiled this code in release mode and ran 4 times to check the output for comparison purpose.

267914296

Time taken in ms : 1556

267914296

Time taken in ms : 0

267914296

Time taken in ms : 1541

267914296

Time taken in ms : 0

267914296

Time taken in ms : 1609

267914296

Time taken in ms : 0

267914296

Time taken in ms : 1656

267914296

Time taken in ms : 1

What you notice is order of magnitudes faster if you calculate Fibonacci number in an iterative way instead of a recursive way. It also shows the cost of allocation of a function stack. 

If you run the same program to calculate Fibonacci number for a smaller value like 20, the difference is so small that it wouldn't matter. Here is the output.

6765

Time taken in ms : 1

6765

Time taken in ms : 0

6765

Time taken in ms : 1

6765

Time taken in ms : 0

6765

Time taken in ms : 0

6765

Time taken in ms : 0

6765

Time taken in ms : 1

6765

Time taken in ms : 0

This output highlights that increase in total time is not linearly related to depth of recursion.

So where does this fit in the world of object oriented programming where you are asked to create modular single responsibility functions. There is a definite value of modular structure as keeps the Software extensible, robust, and testable. 

As long as your application is not using n layers of function calls to perform trivial tasks, you will be good as the cost is not as high. There are runtime level capabilities in each platform (Java, .NET etc.) where if you chose the right options, nothing bad will happen. 

A typical example in .NET is user input validation which is a frequent and (mostly) trivial operation. You can utilize model binding, custom object validators, or model state to keep validation at the entry point instead of hiding it in a utility class which is 5 layers down.