## Saturday, October 18, 2008

### Comparing MSIL of F# Versus C#

Comparing MSIL:

To get a good understanding of what is going on "under the covers" of our example from last week, a person can view the generated MSIL (Microsoft Intermediate Language). While there are several options for doing this, I chose to use Reflector.

Here's a review of the F# code as well as the C# equivalent:

F#:

Test:

[TestMethod]
public void CanCalculateNumberSquared()
{
int
result = FSharpSample.CalculateNumberSquared(2);
Assert
.AreEqual(result, 4)
}

Code:

#light
let
CalculateNumberSquared x = x*x;;

Here's the C# code.

Test:

[TestMethod]
public void
CanCalculateNumberSquaredInCSharp()
{
CSharpSample.CSharpSample cSharpSample = new CSharpSample.CSharpSample();
int
result = CSharpSample.CalculateNumberSquared(2);
Assert
.AreEqual(result, 4);
}

Code:

public class CSharpSample
{
public int
CalculateNumberSquared(int numberToSquare)
{
return
numberToSquare * numberToSquare;
}
}

Here is the managed code with comments explaining what is happening:

C#:

 `.method public hidebysig instance int32 CalculateNumberSquared(int32 numberToSquare) cil managed { .maxstack 2 // maximum number of elements that can be pushed to the valuation stack.locals init ( int32 CS\$1\$0000) // this is a local variable of type int32 L_0000: nop // do nothing -- indicates compiled in debug modeL_0001: ldarg.1 // push argument 1 onto the stack L_0002: ldarg.1 // push argument 1 onto the stack (multiplying a number by itself) L_0003: mul // multiply valuesL_0004: stloc.0 // pop a value from the stack into a local variable L_0005: br.s L_0007 // go to labl L_0007L_0007: ldloc.0 // push local variable at index 0 onto the stackL_0008: ret // return the value from the stack (if there is one) and return from the method}`
F#:

`.method public static int32 CalculateNumberSquared(int32 x) cil managed {     .maxstack 4 // maximum number of elements that can be pushed to the valuation stackL_0000: nop // do nothing -- indicates compiled in debug modeL_0001: ldarg.0 // push argument 0 onto the stack     L_0002: ldarg.0 // push argument 0 onto the stack     L_0003: mul // multiply valuesL_0004: ret // return the value from the stack (if there is one) and return from the method}`

This first thing that I noticed when comparing the managed code from each example, was that
the F# code is more succinct. Each is accomplishing the same goal, but the CIL generated from
F# is five lines less that that which was generated from the C# example.
The second thing I
noticed was that the F# method is static while the C# method is not. To ensure that we are
comparing apples to apples, a new static method was generated in the C# example.

Here's the code:

Test:

[TestMethod]

public void
CanStaticCalculateNumberSquaredInCSharp()

{
int
result = CSharpSample.StaticCSharpSample.CalculateNumberSquared(2);
Assert
.AreEqual(result, 4);

}

Code:

public static class StaticCSharpSample

{

public static int CalculateNumberSquared(int numberToSquare)
{
return
numberToSquare * numberToSquare;
}
}

MSIL:
 `.method public hidebysig static int32 CalculateNumberSquared(int32 numberToSquare) cil managed { .maxstack 2 // maximum number of elements that can be pushed to the valuation stack.locals init (  int32 CS\$1\$0000) // this is a local variable of type int32 L_0000: nop // do nothing -- indicates compiled in debug mode L_0001: ldarg.1 // push argument 1 onto the stack L_0002: ldarg.1 // push argument 1 onto the stack multiplying a number by itself) L_0003: mul // multiply valuesL_0004: stloc.0 // pop a value from the stack into a local variable L_0005: br.s L_0007 // go to labl L_0007L_0007: ldloc.0 // push local variable at index 0 onto the stackL_0008: ret // return the value from the stack (if there is one) and return from the method}`
As you can see, the MSIL is very similar to that which was generated in our first example.
While we could probably find a way to make the C# example generate the same managed
code as the F# example, it is clear that the F# example requires less work and less lines of code
to generate the more succinct result.