As Rex Kerr noted, this is a Scala compiler that uses tail call optimization. If you want to know what compiles at the end, you can run the compiler with an additional argument:
scalac -Xprint:tailcalls yourfile.scala
This will print an intermediate view after the tailcalls compiler tailcalls . (If you want to learn about all the steps, you can also run scalac -Xshow-phases .) For example, at 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 foo function):
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 _foo(_$this,l) looks like a function definition, but itβs really a label, and the _foo(TailRec.this, xs) βcallβ _foo(TailRec.this, xs) is actually a jump to that label. In short, the compiler rewrote the recursive call into what the while loop really is.
The compiler will automatically apply optimization when possible. If you want to make sure that the function is overwritten correctly, you can annotate it with @tailrec , and the compiler throws an error if it cannot optimize it.
source share