3 ms·
The point of the tail call is to not push an item on the stack frame. That is why tail call is an optimization you can perform when there are no other operatio
by kenjackson 15y ago
The point of the tail call is to not push an item on the stack frame. That is why tail call is an optimization you can perform when there are no other operations after the tail call. You can jump to the next instruction and be done with it.
But if the tail call is in a try-finally block the "tail call" is not actually the tail. There is more code that needs to be run after the execution of the tail call. The code has to return back from the tail call and execute the finally code.
What you thought was a tail call is actually no longer a tail call at all.
- nxn 15y agoI was under the impression that the article stated that a CALL to a recursive function inside of the try-* block would prevent it from being done with a tail call, and not that the recursive function contained a wrapping try-* block in its body. I think I may have understood wrong what the article was saying.
- kenjackson 15y agoI was under the impression that the article stated that a CALL to a recursive function inside of the try- block would prevent it from being done with a tail call* Yes, that statement is correct and what we're talking about. Having a try-finally in the body of the tail-call function shouldn't make a difference. To be clear: try { ... tailcall(...); } finally { ... } That could block tail call optimization.
- profquail 15y agoAccording to the .NET CLR spec, you're not allowed to have a tailcall within a protected ("try") block or it's handler. On the other hand, tail-calls can be optimized into a while loop, and the F# compiler does this in some cases (check out the IL it produces), so then you could have a recursive tail-call within a try/finally there, it just wouldn't be using the 'tail.call' / 'tail.callvirt' / 'tail.calli' OpCode.
- nxn 15y agoRight, I completely see how that would prevent it from qualifying as a tail call, my misunderstanding was still different though. For some reason I thought that even if the recursive function was defined within the try-catch block (as below) it would prevent it from using a tail call: try let rec func ... = ... func( ... ) let result = func( ... ) with | ex -> ... I don't know exactly how I ended up thinking that, seems a bit silly in retrospect.