The function send()
in the following example calls itself recursively:
internal inner class RouteSender(
val features: List<Feature>,
val exchange: GrpcUniExchange<Point, RouteSummary>
) {
var result: AsyncResult<RouteSummary>? = null // Set in stub for recordRoute.
fun send(numPoints: Int) {
result?.let {
// RPC completed or err'd before sending completed.
// Sending further requests won't error, but they will be thrown away.
return
}
val index = random.nextInt(features.size)
val point = features[index].location
println("Visiting point ${RouteGuideUtil.getLatitude(point)}, " +
"${RouteGuideUtil.getLongitude(point)}")
exchange.write(point)
if (numPoints > 0) {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
} else {
exchange.end()
}
}
}
It can be re-written so that the last operation performed is the recursive call to itself:
...
if (numPoints <= 0) {
exchange.end()
} else {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
}
...
Yet, if I mark it as a tailrec
function, I get a warning that the recursive call is not a tail call. This doesn't stop compilation of the successful running of the program. However, why is this not a tail call?
The documentation says:
To be eligible for the
tailrec
modifier, a function must call itself as the last operation it performs. You cannot use tail recursion when there is more code after the recursive call, and you cannot use it within try/catch/finally blocks.
This is not within a try/catch/finally block and there is no more code after the recursive call. What is it that means this code block is ineligible for tail recursion optimisation?
I'll take a stab at answering my own question, in that it has no return value. Based on this discussion, that's about all I can think of. Thoughts?