As Rex Kerr pointed out, this is the Scala compiler applying a tail call optimization. If you want to know what is compiled in the end, you can run the compiler with an extra argument:
scalac -Xprint:tailcalls yourfile.scala
This will print the intermediate representation after the tailcalls
compiler phase. (If you want to learn about all phases, you can also run scalac -Xshow-phases
.) For example, on the following input:
object TailRec {
def foo(l : List[Int]) : Unit = l match {
case Nil => Thread.dumpStack()
case x :: xs => println(x); foo(xs)
}
}
The compiler will print (for the function foo
):
def foo(l: List[Int]): Unit = {
<synthetic> val _$this: TailRec.type = TailRec.this;
_foo(_$this,l){
l match {
case immutable.this.Nil => java.this.lang.Thread.dumpStack()
case (hd: Int, tl: List[Int])collection.immutable.::[Int]((x @ _), (xs @ _)) => {
scala.this.Predef.println(x);
_foo(TailRec.this, xs)
}
}
}
}
The part _foo(_$this,l)
looks like a function definition, but it's really a label, and the "call" _foo(TailRec.this, xs)
is in fact a jump to that label. So in short, the compiler rewrote a recursive call into what really is a while loop.
The compiler will apply the optimization automatically when it can. If you want to make sure that a function is properly rewritten, you can annotate it with @tailrec
, and the compiler will produce an error if it cannot optimize it.