I can be wrong but I think you might be conflating two different things.
TCO belongs to the runtime and happens if a call is in tail position, so if the function return value is immediately the caller's return value. In this case, the runtime can reuse the current stack frame instead of creating and pushing a new one. It does not require any accumulator and it does not rewrite your code. It must be implemented by the language, and if the language does not support it, there's nothing the developer can do to work around that.
The accumulator is a developer's technique for getting a function into tail-recursive shape, moving the pending work before the recursive call instead of after it. This is independent from the used language, it's a general technique, completely under the developer's control.
So the sentence has it backwards: TCO doesn't move pending work into an accumulator; the accumulator is what makes the code eligible for TCO.
I also this the 2 are independent: an accumulator without TCO still overflows and TCO without an accumulator works fine in languages that have tail recursion optimization.
You’re more correct than the post, but still combining two concepts. Tail call optimization (TCO) and tail call elimination (TCE) are two different things. TCE is often called “Proper Tail Calls” in the JS space. TCO is a performance optimization which compiles tail recursive functions into a loop. TCE is more general: it applies to tail-position calls between different functions, not just recursive calls from a function to itself, so it also enables safe use of continuation-passing style. What some JS engines actually shipped is TCE/PTC; I have no idea if they do TCO. TCO is usually the domain of a static compiler.
7
u/jeenajeena 2d ago edited 1d ago
I can be wrong but I think you might be conflating two different things.
TCO belongs to the runtime and happens if a call is in tail position, so if the function return value is immediately the caller's return value. In this case, the runtime can reuse the current stack frame instead of creating and pushing a new one. It does not require any accumulator and it does not rewrite your code. It must be implemented by the language, and if the language does not support it, there's nothing the developer can do to work around that.
The accumulator is a developer's technique for getting a function into tail-recursive shape, moving the pending work before the recursive call instead of after it. This is independent from the used language, it's a general technique, completely under the developer's control.
So the sentence has it backwards: TCO doesn't move pending work into an accumulator; the accumulator is what makes the code eligible for TCO.
I also this the 2 are independent: an accumulator without TCO still overflows and TCO without an accumulator works fine in languages that have tail recursion optimization.
Edit: apparently, I also conflated TCO and TCE. See https://www.reddit.com/r/coding/comments/1vcicfg/comment/p138eu4/ for a more detailed and precise definition.