In a recent StackOverflow answer, I gave the following recursive code:
def retry[T](n: Int)(fn: => T): T = {
try {
fn
} catch {
case e if n > 1 =>
retry(n - 1)(fn)
}
}
If I add the @tailrec annotation, I get:
Could not optimize @tailrec annotated method retry: it contains a
recursive call not in tail position.
I was able to hack a tail-recursive alternative, but I still wonder why this didn’t optimize. Why not?
To be tail-recursion optimized, this has to be transformed into something like the following:
When it executes the
GOTOto loop, it has to leave to scope of thecatchblock. But in the original recursive version, the execution of the recursive call is still within thecatchblock. If the language allows that this could ever potentially change the meaning of the code, then this wouldn’t be a valid optimization.EDIT: From discussion with Rex Kerr in the comments, this is a behaviour-preserving transformation in Scala (but only when there is no
finally). So apparently it’s just that the Scala compiler doesn’t yet recognise that the last call of acatchblock where there is nofinallyis in a tail-call position.