I'm reading Programming in Scala by M. Odersky and he says that
Functions like approximate, which call themselves as their last action, are called tail recursive.
So, I tried this:
object Main extends App {
    implicit val mc = new MyClass(8)
    val ti = new TestImplct
    ti.test
}
class TestImplct {
  def test(implicit mc : MyClass): Unit = {
    println(mc.i)
    mc.i -= 1
    if(mc.i < 0){
      throw new IllegalArgumentException
    }
    test
  }
}
class MyClass(var i : Int)
IDEONE DEMO
But it generates the following stack trace
 Exception in thread "main" java.lang.IllegalArgumentException
    at TestImplct.test(Main.scala:13)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
Which means that it generates a new stack frame for each recursive call. But the last action is to call to itself. What's wrong and how to make it tail-recursive?
Why doesn't compiler do tail-call optimization?
You can try marking the method with @tailrec annotation. If you do that, compilation will fail and will show you why compiler couldn't optimize this to be tail recursive:
Main.scala:12: error: could not optimize @tailrec annotated method test: it is neither private nor final so can be overridden
Indeed, if you make the method final, it works as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With