13

Based on the rich wealth of stackoverflow, I've been getting on and off answers on whether the tail recursive optimization is done to specifically c# code. A few of the questions appeared to talk about

  1. Speculation of the optimization in newer versions of .net that were being released
  2. Building application as a x64bit application to achieve the optimization
  3. Switching from a debug build to a release build in Visual Studio to achieve the optimization
  4. No optimization at all and that the microsoft community had claimed that they wouldn't do tail recursive optimization for "security issues" (didn't really understand this one)
  5. It happens by random

So as of C# 4.0 (Visual Studio 2013/2015) how does one ensure the tail recursive optimization if one can ensure it at all?

Bennett Yeo
  • 819
  • 2
  • 14
  • 28
  • 3
    It generally adds a lot of value to these posts when you link the other questions and answers you came across so we can follow your train of thought and path you took to reach your question. – Travis J Apr 10 '15 at 21:30
  • 1
    The current version of C# is 5, version 6 is available in VS 2015 previews. – Mike Zboray Apr 10 '15 at 21:31
  • @TravisJ I was going to try to link the other questions, but wasn't really sure if I could track them down b/c I viewed them over a significant period of time. – Bennett Yeo Apr 10 '15 at 21:42
  • Useful conversation about it by Jon skeet and Scott Hanselman on 2016 https://youtu.be/H2KkiRbDZyc?t=3302 – Daniel B Sep 19 '17 at 18:13

1 Answers1

23

There are different levels at which the tail call optimization can be supported. The JIT is really responsible for most of the optimizations in any .NET program. The C# compiler itself doesn't even do method inlining, that is the JIT compiler's responsibility. The C# compiler could use the Tailcall IL opcode designating a call as a tail call, however I believe no version of C# compiler does this. The JIT compiler is permitted to make tail call optimizations whenever it sees fit. In particular, I believe only the 64-bit JIT does this. This blog post outlines a number of scenarios in which JIT64 cannot use tail call optimization. I'm sure the criteria may be subject to change since they are working on a rewrite of the JIT compiler, codenamed RyuJIT.

If you want a short example of a program that can use TCO try this:

class Program
{
    static void Main(string[] args)
    {
        Test(1);
    }

    private static void Test(int i)
    {
        Console.WriteLine(i);
        Test(i + 1);
    }
}

Set the project to build Release/x64 (or AnyCPU w/o prefer 32-bit) and start without the debugger attached. The program will run forever. If I do not do all of those things, then I get a stackoverflow exception around 20947.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • 1
    Second link references the same as first one. Did you mean this? http://blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11/tail-call-improvements-in-net-framework-4.aspx Also, good post: http://stackoverflow.com/questions/15864670/generate-tail-call-opcode – Erti-Chris Eelmaa Apr 10 '15 at 21:45
  • @Erti-ChrisEelmaa Fixed the link, which is also referenced in the post you linked to. – Mike Zboray Apr 10 '15 at 21:49
  • So to ensure there is even a likelihood of a tail recursive optimization by the JIT compiler, set it to 64 bit build? Additionally, is there anything immediate things (keywords, attribute tags) one could add to increase the probability of the optimization? – Bennett Yeo Apr 10 '15 at 21:54
  • 1
    @KiroYakuza - You could consider forcing the optimization by storing the method calls. – Travis J Apr 10 '15 at 21:57
  • 1
    @KiroYakuza It doesn't necessarily need to be an x64 build. It can be Any CPU (w/o prefer 32-bit) on a 64-bit platform. You should run a Release build without the debugger attached. I do know of any attributes that affect whether the JIT deems a method fit for TCO. – Mike Zboray Apr 10 '15 at 21:58
  • @TravisJ what does "storing the method calls" mean? – Bennett Yeo Apr 10 '15 at 22:00
  • @KiroYakuza - Eric Lippert gives a pretty good example of it here: http://stackoverflow.com/a/2201064/1026459 – Travis J Apr 10 '15 at 22:03
  • @TravisJ looks like I already knew the concept of 'storing method calls' without knowing the term for them. It is `recursive(x-1, runningTotal)` vs. `x+recursive(x-1)`. – Bennett Yeo Apr 11 '15 at 01:10
  • Bingo! the support for tail recursive call optimization is actually there. I was under an impression that .net doesn't support this as C# doesn't do it. Great peace of information. I was able to run it on Visual Studio 2010 for release + x64 configuration and it actually works! – RBT Sep 23 '16 at 01:18
  • The 2007 blog post appears to be (unsurprisingly) out of date. There's some interesting newer discussion on GitHub [here](https://github.com/dotnet/csharplang/issues/2544) and an active language-enhancement proposal [here](https://github.com/dotnet/csharplang/issues/2304). – Stephen Kennedy Apr 07 '20 at 18:58