Inferencia de tipos en Java 8

30

¿La introducción de la nueva notación lambda (ver, por ejemplo, este artículo ) en Java 8 va a requerir algún tipo de inferencia de tipos?

Si es así, ¿cómo afectará el nuevo sistema de tipos al lenguaje Java en su conjunto?

Giorgio
fuente

Respuestas:

47

Hay bastante información incorrecta en la respuesta de Ratchet Freak y en su hilo de comentarios. Responderé aquí en una respuesta, ya que un comentario es demasiado pequeño. Además, dado que esta es una respuesta después de todo, intentaré responder la pregunta original también. (Sin embargo, tenga en cuenta que no soy un experto en sistemas de tipos).

Primero, las respuestas cortas a la pregunta original son Sí y No. Sí, Java 8 tendrá considerablemente más inferencia de tipos que Java 7, y No, no hay un sistema de tipos "nuevo" en Java 8, aunque hay algunos cambios menores. .

Java 8 seguirá estando estáticamente tipado y seguirá teniendo la dicotomía entre clases e interfaces. No hay nuevos tipos, como los tipos de función. El tipo de lambda es esencialmente una "interfaz funcional" que es una interfaz ordinaria con un único método abstracto.

Las interfaces ahora pueden tener código en forma de métodos predeterminados, pero el modelo de herencia única de clases y herencia múltiple de interfaces sigue siendo el mismo. Hay algunos ajustes, por supuesto, como las reglas para la resolución de métodos en presencia de métodos predeterminados, pero los fundamentos no cambian.

Cualquier tipo inferido por la inferencia de tipos podría escribirse explícitamente. Para usar el ejemplo de Ratchet Freak ,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

es básicamente azúcar para

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

Entonces , la afirmación de sparkleshy "la inferencia de tipos no requiere ninguna extensión del sistema de tipos" es básicamente correcta.

Pero para volver al azúcar sintáctico, repetiré mi afirmación de que una expresión lambda no es azúcar sintáctico para una clase interna anónima. Ratchet freak declaró que una expresión lambda se traduce en una instanciación anónima de clase interna, y Sparkleshy simplemente reafirmó que una lambda es azúcar sintáctica para una clase interna anónima, pero estas declaraciones son incorrectas. Probablemente se basan en información desactualizada. Las primeras implementaciones de lambda implementaron lambdas de esta manera, pero las cosas han cambiado.

Las expresiones lambda son semánticamente diferentes de las clases internas, y se implementan de manera diferente a las clases internas.

Las expresiones lambda son semánticamente diferentes de las clases internas en un par de formas. La evaluación de una expresión lambda no necesita crear una nueva instancia cada vez. También tienen diferentes semánticas de captura, por ejemplo, capturan esto de manera diferente. En una clase interna, esta es la instancia de clase interna, mientras que en una lambda, esta es la instancia de cierre. Considera lo siguiente:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

En una reciente compilación JDK 8 lambda (utilicé b69 ), el resultado será algo similar a lo siguiente:

CaptureThis$1@113de03
outer

Además, las expresiones lambda se implementan de manera completamente diferente a las clases internas. Si compara la salida desensamblada, verá que el código de clase interno compila directamente a la creación y llama a un constructor de CaptureThis $ 1, mientras que la expresión lambda compila a una instrucción invocada dinámica que proporciona un Runnable a través de medios no especificados. Para una explicación completa de cómo funciona esto y por qué, vea la charla de Brian Goetz en JavaOne 2012 Lambda: A Peek Under The Hood .

Stuart Marks
fuente
2
"capturan esto de manera diferente. En una clase interna, esta es la instancia de clase interna, mientras que en una lambda, esta es la instancia que lo encierra. Considere lo siguiente:" todavía se puede hacer con azúcar sintáctico reemplazando todo thisconMyClass.this
ratchet freak
44
Todo lo que va más allá del ensamblador (y a veces incluso eso) es posiblemente azúcar sintáctica. Pero las lambdas no son azúcar sintáctica para las clases internas (más). Sirven un objetivo similar y tienen algunas similitudes, pero bajo el capó son (observablemente) diferentes.
Joachim Sauer
1
"Las expresiones lambda son semánticamente diferentes de las clases internas, y se implementan de manera diferente a las clases internas": Gracias por la muy buena explicación (+1). Lo que aún no me queda claro es por qué las lambdas no se han implementado como azúcar sintáctica para clases anónimas especiales o, en otras palabras, ¿cuál es la ventaja de la complejidad adicional introducida por la nueva semántica? ¿Qué problema resuelve esto que no se puede resolver con clases internas anónimas? (Pero aún tengo que mirar el enlace que publicaste, tal vez encuentre la respuesta allí.)
Giorgio
1
@Joachim Sauer: Consideraría que el azúcar sintáctico es una nueva sintaxis para una semántica existente. Cuando se introduce una nueva semántica, creo que no se puede hablar sobre el azúcar sintáctico. En este sentido, no creo que se pueda argumentar que todo lo que está más allá del ensamblador es azúcar sintáctico.
Giorgio
3
@Giorgio: respecto a por qué lambda no es solo azúcar sintáctica para clases internas anónimas, resulta que hubo una gran discusión sobre esto. Este correo de Brian Goetz resume la decisión: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL; DR deja la puerta abierta para la evolución futura y hoy obtenemos un mejor rendimiento. Goetz en realidad está respondiendo una pregunta relacionada: ¿Son los objetos lambdas? Pero si la respuesta es No o incluso Quizás eso implica que no pueden ser azúcar para las clases internas.
Stuart Marks