Why is this throwing stack overflow exception?
... despite it being tail-call-optimizable?
def areStreamsEqual(stream1: InputStream, stream2: InputStream): Boolean =
{
val one = stream1.read()
val two = stream2.read()
if(one != two)
false
else if(one == -1 && 开发者_如何学编程two == -1)
true
else
areStreamsEqual(stream1, stream2)
}
Is there anyway to force the Scala compiler to do a tail call optimization here?
Thanks to pst for the comment about @tailrec. Given that annotation scala compiler error message explains the reason for not optimizing the method.
<filename>.scala:64: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden
def areStreamsEqual(stream1: InputStream, stream2: InputStream): Boolean =
making the method private sorts it out
I suspect that on the byte code level, there are two instructions for calling methods: virtual_call and tail_call.
For anyone trying to recreate the compiler error in the REPL, you have to wrap the method in a class like this:
class Test {
@annotation.tailrec def areStreamsEqual(stream1: InputStream, stream2: InputStream): Boolean =
{
val one = stream1.read()
val two = stream2.read()
if(one != two)
false
else if(one == -1 && two == -1)
true
else
areStreamsEqual(stream1, stream2)
}
}
If you just plug the method into the REPL, it will be TCO'd just fine, since the method outside of a class can't be overridden.
精彩评论