Kotlin: ¿Por qué esta function no es elegible para la recursion de queue?

La function send() en el siguiente ejemplo se llama recursivamente:

 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() } } } 

Se puede reescribir para que la última operación realizada sea la llamada recursiva a sí misma:

 ... if (numPoints <= 0) { exchange.end() } else { vertx.setTimer(random.nextInt(1000) + 500L) { _ -> send(numPoints - 1) } } ... 

Sin embargo, si lo marco como una function tailrec , recibo una advertencia de que la llamada recursiva no es una llamada tailrec . Esto no detiene la compilation de la ejecución exitosa del progtwig. Sin embargo, ¿por qué esto no es una llamada de queue?

La documentation dice:

Para ser elegible para el modificador de tailrec , una function debe llamarse a sí misma como la última operación que realiza. No puede usar recursion final cuando hay más código después de la llamada recursiva, y no puede usarlo en los bloques try / catch / finally.

Esto no está dentro de un bloque try / catch / finally y no hay más código después de la llamada recursiva. ¿Qué significa que este bloque de código no es elegible para la optimization de recursion de queue?

Voy a intentar responder mi propia pregunta, ya que no tiene ningún valor de retorno. Basado en esta discusión, eso es todo lo que puedo pensar. ¿Pensamientos?

Aunque su método parece contener una llamada a sí mismo, en realidad no es un método recursivo.

La llamada para send aparece dentro de un cierre. Eso significa que no se invoca de inmediato. Solo se invocará cuando se invoque el cierre en sí. En tu caso, eso se hace con un timer. Se llevará a cabo fuera de la stack de llamadas actual, y probablemente incluso fuera del hilo actual.

En cualquier caso, la última llamada es la llamada a vertx.setTimer .

Kotlin permite funciones de cierre en línea que utiliza para varias de sus funciones de biblioteca, como para cada uno. El tailrec podría funcionar si se llama desde un cierre en línea, después de que todo el retorno de un cierre en línea retorna desde la function externa.

Sin embargo, como se señaló anteriormente, esta es una function de callback del timer, por lo que, por definición, no puede ser una llamada en línea, y no ser recursiva de queue.