Why is tail call optimization not occurring here?
Asked Answered
D

1

12

We are using recursion to find factors and are receiving a StackOverflow exception. We've read that the C# compiler on x64 computers performs tail call optimizations:

JIT definitely does tailcals when running optimized code and not debugging.

Running dotnet --configuration release gets this far in our program:

...                      
7214 is a factor of 1234567890
7606 is a factor of 1234567890
10821 is a factor of 1234567890
11409 is a factor of 1234567890                

Process is terminated due to StackOverflowException.

Why is tail call optimization not occuring?

class Program
{
    static void Main(string[] args)
    {
        const long firstCandidate = 1;
        WriteAllFactors(1234567890, firstCandidate);
    }

    private static void WriteAllFactors(long number, long candidate)
    {
        if (number % candidate == 0)
        {
            System.Console.WriteLine($"{candidate} is a factor of {number}");
        }

        candidate = candidate + 1;
        if(candidate > number / 2)
        {
            return;
        }

        WriteAllFactors(number, candidate);
    }
}
Defelice answered 31/12, 2016 at 2:16 Comment(6)
Doesn't tail call recursion require that you return the value?Housman
@Housman I'm guessing that's a rhetorical question. :)Defelice
There's no return at all; what stops this from running forever?Tyche
@EricLippert Sorry, a recent edit removed the return. Fixed.Defelice
@ShaunLuttin, no it's an "I don't remember the details of tail-call recursion" question.Housman
related, though in different language(s).Erythrism
O
3

VSadov provides the explicit reason for this in his response:

Generally JIT emits tail calls when it finds that profitable.

In addition, he goes on to state:

This is a part that is not expressible in C#. Unlike inlining, which can be forced via attributes, tailcalling cannot be currently forced. If one needs to write the code like emitted by EmitMethodCall, he cannot use C#.

So the answer is that while tailcalls are definitely available and used, there is no way to either predict when they will be used or force them to be used in C#.

Ouzel answered 31/12, 2016 at 3:9 Comment(1)
I feel surprised that it is not profitable to prevent a StackOverflow exception. If that's the answer, though, then that's the answer.Defelice

© 2022 - 2024 — McMap. All rights reserved.