¿Cuáles son los beneficios y desventajas en los enfoques de C #, Java y Scala para Closures / Lambdas / ...?

30

Me pregunto cuáles son las diferencias de implementación técnica entre C # y Scala y cómo ambas soluciones se comparan con las ideas y preocupaciones de implementación expresadas en el correo electrónico Peek Past lambda de Brian Goetz, enviado a la lista de correo del Proyecto Lambda (JSR 335) .

Desde el correo electrónico:

Exploramos el camino de "quizás las lambdas deberían ser solo instancias de clase interna, eso sería realmente simple", pero finalmente llegamos a la posición de "las funciones son una mejor dirección para el futuro del lenguaje".

y además:

La visión lambdas-son-objetos del mundo entra en conflicto con este posible futuro. La visión del mundo de las lambdas-son-funciones no lo hace, y preservar esta flexibilidad es uno de los puntos a favor de no cargar a las lambdas incluso con la apariencia de objetividad.

Conclusión:

Lambdas-are-functions abre puertas. Lambdas-are-objects los cierra.
Preferimos ver esas puertas abiertas.

Y un comentario de una persona en el hilo de Reddit dice:

De hecho, envié un correo electrónico a Neal Gafter sobre esto y para mi comprensión limitada de su explicación C # y el diseño actual de Java son bastante similares en el sentido de que los Delegados son en realidad objetos y no tipos de funciones. Parece que él cree que Java debería aprender de las desventajas de las lambdas de C # y evitarlas (al igual que C # aprendió de las desventajas de Java y las evitó al principio).

¿Por qué el enfoque de "Lambdas-son-funciones" permite más oportunidades en el futuro que "Lambdas-son-objetos"? ¿Alguien puede explicar qué diferencias existen y cómo influirían en cómo se escribiría el código?

Al ver que las cosas en Scala "simplemente funcionan", sigo pensando que me falta algo sobre los enfoques adoptados / propuestos en C # / Java (8), ¿probablemente esté relacionado con preocupaciones sobre la compatibilidad con versiones anteriores?

soc
fuente
1
Esto es interesante. Dado que el sistema de tipos Javas no tiene un concepto de funciones a partir de ahora, esto significaría que uno tenía que introducir esto primero. Podría ser posible que el lenguaje se vuelva demasiado complejo con esto.
Ingo
¿No son las funciones las instancias de alguna interfaz? ¿Qué tienen de especial?
soc
Lisp / Scheme / Clojure puede modelar objetos, mientras que Java / C # no puede modelar la anidación arbitraria de funciones. Python parece tener lo mejor de ambos mundos, sin embargo.
Trabajo

Respuestas:

15

Creo que la discusión sobre objetos versus funciones es una pista falsa. Si la pregunta es: "¿Es una lambda una función o un objeto?" La respuesta debería ser .

Ese es el punto de las funciones de primera clase: no se tratan de manera diferente que cualquier otro tipo. Java ya se las arregla para ignorar principalmente las diferencias entre los objetos y los tipos primitivos (y Scala lo hace aún mejor), por lo que si una lambda es una subclase de Object o es un nuevo tipo primitivo o algo más no es realmente importante para el lenguaje. Lo importante es que puede poner sus lambdas en colecciones, pasarlas para que las llamen, llamarlas y hacer cualquier otra cosa que desee hacer con un objeto o un método.

Scala logra esto mediante el uso de un objeto contenedor que tiene un método llamado applyque se puede invocar con solo (), haciendo que se vea como una llamada a un método. Esto funciona espléndidamente; la mayor parte del tiempo no necesita preocuparse si tiene un método o si está llamando a la aplicación de un objeto de función.

Rex Kerr
fuente
9

Por lo que entiendo, se trata más de cómo se consideran las lambdas en el nivel de idioma primario. Como dice el correo electrónico,

Puede pensar que el diseño actual está estrechamente vinculado a una caja de objetos para lambdas (tipos SAM), lo que los convierte en objetos efectivos de todos modos. Pero esto se ha ocultado cuidadosamente de la superficie para permitirnos considerar lambdas 'desnudas' en el futuro, o considerar otros contextos de conversión para lambdas, o integrar lambdas más estrechamente en construcciones de control. No estamos haciendo eso ahora, y ni siquiera tenemos un plan concreto para hacerlo, pero la posibilidad de hacerlo en el futuro es una parte crítica del diseño.

Creo que eso resume muy bien tu pregunta. Si declaras que "las lambdas son objetos", entonces son solo un objeto de una clase en particular y estás atascado con eso. Por otro lado, si declaras "lambdas son funciones", semánticamente tienes un campo de juego mucho más rico. Java 1.7 podría compilarlos en objetos, por lo que son prácticamente idénticos en ese punto.

Pero Java 1.8, o 1.9, podría traer cambios en el lenguaje (como los tipos estructurales reificados) que permitan que las funciones se usen de maneras mucho más flexibles. Si las "lambdas fueran objetos", estos cambios no serían compatibles con versiones anteriores y tendrías que introducir un nuevo concepto por completo, para no romper el código existente de las personas. Pero si javacsolo estaba convirtiendo silenciosamente lambdas en objetos detrás de escena, el nuevo javacpuede convertirlos a lo que quiera, siempre que la semántica siga vigente.

Andrzej Doyle
fuente
lamdas en C #! = de los delegados. El compilador tiene la opción de compilarlos en delegados o en árboles de expresión. ambos son de hecho gráficos de objetos, pero no están compilados en una "clase particular" ni siquiera en una clase de un árbol de herencia particular
Rune FS
Si lo entiendo correctamente, compilar el lambda en una clase interna del objeto asociado con él lo vincula a ese objeto, por lo que en el futuro si Java introdujera funciones de orden superior (funciones en el mismo nivel de objetos) entonces usted no podría usar la implementación de clase interna, y habría una inconsistencia. No creo que Java tenga funciones de orden superior en el corto plazo.
mwolfetech
@mwolfetech: Hasta donde yo sé, ya están planeados para Java 8 con métodos de defensa. Quieren añadir cosas como foreach, map, filtera las colecciones.
soc
@soc Buen punto, es difícil mantenerse al día con el número de JSR y si realmente completarán y harán una versión objetivo del JDK. Parece que los métodos de defensa podrían ser parte del mismo JSR. Con respecto a este JSR , encontré útil la publicación del estado de Lambda de Brian Goetz : explica los tipos de SAM y los pensamientos actuales para implementar expresiones lambda.
mwolfetech
"pensamientos actuales" mhhh, ¿no es obsoleta esa publicación de 2010 ahora?
soc
5

Sobre todo, él simplemente no quiere comprometerse demasiado pronto con algo. No veo ninguna razón más allá del borrado que presentó, pero esa es una razón muy fuerte.

No me gustan los tipos de función, me encantan los tipos de función, pero esos tipos de función lucharon mal con un aspecto existente del sistema de tipos Java, el borrado. Los tipos de funciones borradas son lo peor de ambos mundos.

Considere estos métodos en Scala Regex:

def replaceAllIn (target: CharSequence, replacer: (Match)  String): String
def replaceSomeIn (target: CharSequence, replacer: (Match)  Option[String]): String

Sería más simple si fueran simplemente esto:

def replace (target: CharSequence, replacer: (Match)  String): String
def replace (target: CharSequence, replacer: (Match)  Option[String]): String

Desafortunadamente, eso no es posible, porque esas dos funciones son idénticas bajo borrado. Pero, bueno, estas funciones hacen cosas algo diferentes, por lo que un nombre diferente podría ser lo suficientemente justo.

Sin embargo, a Matches algo muy útil, pero la mayoría de las veces desea que coincidan Stringo la lista de subgrupos. Nos gustaría tener esto:

def replaceAllIn (target: CharSequence, replacer: (String)  String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String])  String): String
def replaceAllIn (target: CharSequence, replacer: (Match)  String): String

No es posible, debido a la eliminación. Elegí este ejemplo en particular porque estaba directamente involucrado en él, pero he visto al menos media docena de preguntas sobre Stack Overflow, donde la gente pregunta por qué una sobrecarga es ilegal, causada por este problema exacto.

Y, luego, considere que la coincidencia de patrones de Scala y Java instanceofson efectivamente inútiles debido a la eliminación.

Creo que es justo retrasar los tipos de funciones hasta que se aborde este problema. Después de todo, hay muchos lenguajes que lo tienen en la JVM, y no es que Java sea un lenguaje que evoluciona rápidamente.

Daniel C. Sobral
fuente
Bueno, si el tipo de borrado es el único problema que tienen, ¿qué planean hacer? Romper todos los códigos de este planeta ya no se consideraba una opción para Java 5 ...
Soc
@soc ¡Estoy tan contento de no estar en sus zapatos! Pero ese era Sun, este es Oracle. Oracle nunca ha tenido ningún reparo en hacer cambios importantes entre las versiones principales, e incluso menores, de su producto principal.
Daniel C. Sobral
Tal vez deberían cambiar el nombre del idioma y comenzar a desarrollar un nuevo idioma, dejando de lado la compatibilidad con versiones anteriores. Por lo tanto, uno tendría los beneficios de un nuevo idioma sin la necesidad de jugar con un idioma antiguo y bien establecido. Después de todo, esto es lo que hicieron Scala y Clojure.
Giorgio
@Giorgio Eso sería un poco inútil. Bueno, algunas de las personas que son responsables de lo que es hoy en día Java hicieron eso, sino que, como usted ha dicho, no son alternativas. Pero las personas responsables de Java tienen que mejorar el propio Java , después de todo, son responsables de ello. La única alternativa es simplemente abandonar Java y renunciar a todos los beneficios que resultan de controlarlo.
Daniel C. Sobral
@Daniel C. Sobral: OMI, un lenguaje de programación es un poco como una pieza de software: al principio puede estar limpio y bien diseñado, pero cuanto más juegues con él, más desordenado. Así que creo que sería interesante para los desarrolladores congelar Java como lenguaje y concentrar el desarrollo en (1) crear nuevas bibliotecas o mejorar las existentes, (2) mejorar la JVM (si es posible), (3) desarrollar nuevos lenguajes . Pero como dijiste, hay personas que son responsables de Java y que quieren seguir vendiendo actualizaciones. Entonces lo van a extender para mantenerlo "fresco". Solo mis 2 centavos.
Giorgio