¿La JVM evita las optimizaciones de llamadas de cola?


99

Vi esta cita sobre la pregunta: ¿Cuál es un buen lenguaje funcional sobre el que construir un servicio web?

Scala, en particular, no admite la eliminación de llamadas finales, excepto en funciones auto-recursivas, lo que limita los tipos de composición que puede hacer (esta es una limitación fundamental de la JVM).

¿Es esto cierto? Si es así, ¿qué tiene la JVM que crea esta limitación fundamental?

Respuestas:


74

Esta publicación: ¿ Recursión o iteración?podría ayudar.

En resumen, la optimización de la llamada final es difícil de realizar en la JVM debido al modelo de seguridad y la necesidad de tener siempre disponible un seguimiento de pila. En teoría, estos requisitos podrían ser compatibles, pero probablemente requerirían un nuevo código de bytes (consulte la propuesta informal de John Rose ).

También hay más discusión en el error de Sun # 4726340 , donde termina la evaluación (de 2002):

No obstante, creo que esto podría hacerse, pero no es una tarea pequeña.

Actualmente, se está trabajando en el proyecto de la máquina Da Vinci . El estado del subproyecto de la llamada de cola aparece como "proto 80%"; es poco probable que lo haga en Java 7, pero creo que tiene muchas posibilidades en Java 8.


No seguí bien la explicación. Pensé que el compilador implementó la optimización de la llamada final. Suponiendo que tiene una función que podría ser optimizada por el compilador, también podría tener una función no recursiva equivalente que implemente la misma funcionalidad usando un bucle, ¿correcto? Si es así, ¿no podría hacerlo el compilador? No puedo seguir la dependencia de la JVM. ¿Cómo se compara esto con un compilador de Scheme que generó código i386 nativo?
Gautham Ganapathy

4
@Gautham: Mi declaración sobre la depuración se refería al uso de trampolines como solución para la falta de eliminación de llamadas de cola en la JVM. La eliminación de llamadas de cola puede y se ha implementado en la JVM (Arnold Schaighofer lo hizo en OpenJDK, y también LLVM), por lo que no hay duda de si se puede hacer o no. CLR de Microsoft, por supuesto, ha apoyado la eliminación de llamadas finales durante 10 años y el lanzamiento de F # ha demostrado que es un cambio de juego. Creo que la respuesta es que la JVM hace tiempo que se estancó.
JD

3
Este es un error común y una excusa que se repite con frecuencia, pero es incorrecto. Se ha establecido bien durante varios años que la seguridad mediante la inspección de la pila (y la provisión de seguimientos de pila útiles) no es incompatible con las llamadas finales adecuadas. Por ejemplo, consulte este documento de 2004. citeseerx.ist.psu.edu/viewdoc/… Downvoting, ya que la respuesta es incorrecta.
Justin Sheehy

5
@JustinSheehy: ¿Qué es incorrecto? La pregunta era: "¿La JVM evita las optimizaciones de llamadas finales?" Y la respuesta es: "No, pero es difícil".
Michael Myers

5
¿sabes si en java8 esto está incluido?
nachokk

27

La limitación fundamental es simplemente que la JVM no proporciona llamadas de cola en su código de bytes y, en consecuencia, no hay una forma directa de que un lenguaje construido sobre la JVM proporcione llamadas de cola por sí mismo. Hay soluciones que pueden lograr un efecto similar (por ejemplo, trampolín) pero tienen el grave costo de un rendimiento terrible y ofuscar el código intermedio generado, lo que hace que un depurador sea inútil.

Por lo tanto, la JVM no puede admitir ningún lenguaje de programación funcional con calidad de producción hasta que Sun implemente las llamadas finales en la propia JVM. Lo han estado discutiendo durante años, pero dudo que alguna vez implementen llamadas de cola: será muy difícil porque han optimizado prematuramente su VM antes de implementar una funcionalidad tan básica, y el esfuerzo de Sun se centra fuertemente en lenguajes dinámicos en lugar de lenguajes funcionales.

Por lo tanto, existe un argumento muy fuerte de que Scala no es un lenguaje de programación funcional real: estos lenguajes han considerado las llamadas finales como una característica esencial desde que Scheme se introdujo por primera vez hace más de 30 años.


5
Hence there is a very strong argument that Scala is not a real functional programming language - el argumento es bastante débil. Claro que sí tail calls [as] an essential feature, y bueno si el hardware subyacente (o máquina virtual) lo admite directamente. Pero son los detalles de la implementación.
Ingo

8
@Ingo: solo si no considera que los desbordamientos de pila en su programa en tiempo de ejecución sean vistos por el usuario como un problema significativo. Según su rastreador de errores, incluso el propio compilador de Scala ha estado plagado de desbordamientos de pila. Así que incluso los desarrolladores de Scala más experimentados todavía se están equivocando ...
JD

7
Está bien ser un defensor de, digamos F #. Pero lo he notado durante mucho tiempo (incluso años antes en usenet) por ser hostil a todo lo que no es F #, y sin embargo, sus elaboraciones muestran que no sabe de lo que está hablando. Como aquí: su argumento parece ser que un lenguaje en el que puedo escribir un programa que aborta con desbordamiento de pila no es funcional. Pero, ¿no podría hacerse el mismo argumento para los lenguajes en los que puedo provocar un desbordamiento de montón? Por lo tanto, el santo F # en sí mismo no se consideraría funcional.
Ingo

7
@Ingo: varios modismos en la programación funcional, como la recursividad mutua y el estilo de paso de continuación, pueden requerir la eliminación de llamadas finales para funcionar. Sin él, sus programas se desbordarán. Si un lenguaje no puede ejecutar código funcional idiomático de manera confiable, ¿es funcional? La respuesta es una llamada de juicio, como usted dice, pero una distinción importante en la práctica. Martin Trojer acaba de publicar una publicación de blog interesante sobre esto: martinsprogrammingblog.blogspot.com/2011/11/…
JD

2
aún así, solo porque la JVM (lamentablemente, no hay duda) no puede hacer llamadas finales, esto no significa que la eliminación de llamadas finales sea imposible. Esto es así como si se dijera que los cálculos de punto flotante solo son posibles en computadoras con FPU.
Ingo

22

Scala 2.7.x admite la optimización de llamadas de cola para la autorrecursión (una función que se llama a sí misma) de métodos finales y funciones locales.

Scala 2.8 también puede venir con soporte de biblioteca para trampoline, que es una técnica para optimizar funciones recursivas mutuas.

Se puede encontrar una gran cantidad de información sobre el estado de la recursividad de Scala en el blog de Rich Dougherty .


¿Puede, por favor, actualizar la pregunta sobre el estado actual de Scala?
om-nom-nom

@ om-nom-nom AFAIK, nada ha cambiado, ni en el lado de Scala ni en el lado de JVM.
Daniel C. Sobral


0

Todas las fuentes apuntan a que la JVM no puede optimizar en el caso de recursividad de cola, pero al leer el ajuste de rendimiento de Java (2003, O'reilly) encontré que el autor afirma que puede lograr un mayor rendimiento de recursividad implementando la recursividad de cola.

Puede encontrar su reclamo en la página 212 (busque 'recursividad de cola', debería ser el segundo resultado). ¿Lo que da?


IBM ha admitido alguna forma de TCO en su implementación de JVM (como una optimización, por lo que no hay garantías). Quizás los autores del ajuste de rendimiento de Java pensaron que esta característica eventualmente sería implementada por todas las JVM. ibm.com/developerworks/java/library/j-diag8.html
llemieng
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.