Tail Recursion is a Code Smell
Posted by Al Sweigart in misc
Here are some of the most widely-used language implementations that do not perform general tail-call optimization by default:
- Python (CPython) – Stock CPython does not eliminate tail calls, so deep tail-recursive functions will still blow the call stack (Wikipedia).
- Java (HotSpot JVM) – The JVM specification doesn’t require tail-call elimination, and HotSpot does not perform it by default (Stack Overflow).
- JavaScript engines (V8 in Chrome/Node.js & SpiderMonkey in Firefox) – Although ES6 says proper tail calls should be supported, V8 and SpiderMonkey both lack PTC/TCO (Reddit).
- Ruby MRI (Matz’s Interpreter) – MRI doesn’t do TCO unless you explicitly enable it via
RubyVM::InstructionSequence
(Stack Overflow). - PHP (Zend Engine) – The default PHP interpreter doesn’t optimize away tail calls (Stack Overflow).
- Perl 5 – Perl’s core runtime doesn’t perform tail-call elimination (Stack Overflow).
- Go (gc compiler) – The Go toolchain does not implement general tail-call elimination (Stack Overflow).
- Rust (rustc) – Rust’s optimizer might sometimes elide tail calls, but TCO is neither guaranteed nor broadly applied (Stack Overflow).
- C# (csc/.NET CLR) – While the CLR supports a tail-call opcode, the C# compiler doesn’t emit it by default (F# does) (Stack Overflow).
In contrast, purely functional runtimes (Scheme, Haskell, Erlang, etc.) and languages targeting the BEAM VM (Elixir, Erlang) almost always guarantee TCO.