A year ago I blogged about Tail Recursion in C# on .NET 2.0. With the public beta of .NET 3.5 now available, I decided to retry my little experiment.
For the experiment I used Beta 1 of .NET 3.5 (version 3.5.20404), which you can get from here. Using the supplied compiler, I compiled the following C# code:
public class TailTest{ public static void Main(){ TailTest f = new TailTest(); f.DoTail(0); } public void DoTail(int n){ int v = n + 1; System.Console.WriteLine(v); DoTail(v); } }
Just running the produced EXE is enough to determine that even with the newest version of Microsoft’s compiler, the program has not been optimized for tail recursion. Just to confirm this findings, I went ahead and decompiled the EXE to IL anyway.
.class public auto ansi beforefieldinit TailTest extends [mscorlib]System.Object { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .method public hidebysig instance void DoTail(int32 n) cil managed { .maxstack 2 .locals init ( [0] int32 num) L_0000: nop L_0001: ldarg.1 L_0002: ldc.i4.1 L_0003: add L_0004: stloc.0 L_0005: ldloc.0 L_0006: call void [mscorlib]System.Console::WriteLine(int32) L_000b: nop L_000c: ldarg.0 L_000d: ldloc.0 L_000e: call instance void TailTest::DoTail(int32) L_0013: nop L_0014: ret } .method public hidebysig static void Main() cil managed { .entrypoint .maxstack 2 .locals init ( [0] class TailTest test) L_0000: nop L_0001: newobj instance void TailTest::.ctor() L_0006: stloc.0 L_0007: ldloc.0 L_0008: ldc.i4.0 L_0009: callvirt instance void TailTest::DoTail(int32) L_000e: nop L_000f: ret } }
From my previous discussion, we can see that the resulting IL lacks the “tail.”. With all the innovation in C# for the upcoming release of .NET 3.5, I was hoping that the outcome from my experiment would have been different.