Always annotate your tail-recursive function with
@annotation.tailrec
.
This will let the compiler know that you expect your function to be tail-recursive, and allow compilation to fail should it not be.
This is important, because there are scenarios where you’d expect a function to be tail-recursive but it really isn’t. Take, for example:
class Foo {
def sum(cur: List[Int], acc: Int): Int = cur match {
case h :: t => sum(t, acc + h)
case _ => acc
}
}
This looks tail-recursive - sum
calls itself in tail position, after all. Turns out, however, that it’s not:
class Foo {
@annotation.tailrec
def sum(cur: List[Int], acc: Int): Int = cur match {
case h :: t => sum(t, acc + h)
case _ => acc
}
}
// error: could not optimize @tailrec annotated method sum: it is neither private nor final so can be overridden
// final def sum(cur: List[Int], acc: Int): Int = cur match {
// ^
Thanks to that error message, we can fix the problem and make sum
propery tail-recursive:
class Foo {
@annotation.tailrec
final def sum(cur: List[Int], acc: Int): Int = cur match {
case h :: t => sum(t, acc + h)
case _ => acc
}
}