Clojure does not perform tail call optimization on its own: when you have a tail recursive function and you want to have it optimized, you have to use the special form
recur. Similarly, if you have two mutually recursive functions, you can optimize them only by using
The Scala compiler is able to perform TCO for a recursive function, but not for two mutually recursive functions.
Whenever I have read about these limitations, they were always ascribed to some limitation intrinsic to the JVM model. I know pretty much nothing about compilers, but this puzzles me a bit. Let me take the example from
Programming Scala. Here the function
def approximate(guess: Double): Double = if (isGoodEnough(guess)) guess else approximate(improve(guess))
is translated into
0: aload_0 1: astore_3 2: aload_0 3: dload_1 4: invokevirtual #24; //Method isGoodEnough:(D)Z 7: ifeq 10: dload_1 11: dreturn 12: aload_0 13: dload_1 14: invokevirtual #27; //Method improve:(D)D 17: dstore_1 18: goto 2
So, at the bytecode level, one just needs
goto. In this case, in fact, the hard work is done by the compiler.
What facility of the underlying virtual machine would allow the compiler to handle TCO more easily?
As a side note, I would not expect actual machines to be much smarter than the JVM. Still, many languages that compile to native code, such as Haskell, do not seem to have issues with optimizing tail calls (well, Haskell can have sometimes due to laziness, but that is another issue).