Inférence de type dans Java 8

30

L'introduction de la nouvelle notation lambda (voir par exemple cet article ) dans Java 8 va-t-elle nécessiter une sorte d'inférence de type?

Si tel est le cas, quel sera l'impact du nouveau système de types sur le langage Java dans son ensemble?

Giorgio
la source

Réponses:

47

Il y a pas mal d'informations incorrectes dans la réponse de Ratchet Freak et dans son fil de commentaires. Je vais répondre ici dans une réponse, car un commentaire est trop petit. Aussi, puisque c'est une réponse après tout, je vais essayer de répondre à la question d'origine aussi. (Notez cependant que je ne suis pas un expert des systèmes de type.)

Premièrement, les réponses courtes à la question d'origine sont Oui et Non. Oui, Java 8 aura beaucoup plus d'inférence de type que Java 7, et Non, il n'y a pas de "nouveau" système de type dans Java 8, bien qu'il y ait quelques changements mineurs .

Java 8 sera toujours typé statiquement, et il aura toujours la dichotomie entre les classes et les interfaces. Il n'y a pas de nouveaux types tels que les types de fonction. Le type d'un lambda est essentiellement une "interface fonctionnelle" qui est une interface ordinaire avec une seule méthode abstraite.

Les interfaces peuvent désormais avoir du code sous la forme de méthodes par défaut, mais le modèle d'héritage unique des classes et d'héritage multiple des interfaces reste le même. Il y a bien sûr certains ajustements, comme les règles de résolution des méthodes en présence de méthodes par défaut, mais les fondamentaux restent inchangés.

Tout type déduit par l'inférence de type peut être écrit explicitement. Pour utiliser l'exemple de ratchet freak ,

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

est essentiellement du sucre pour

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

Donc , sparkleshy déclaration de « l' inférence de type ne nécessite pas d'extension du système de type » est fondamentalement correcte.

Mais pour revenir au sucre syntaxique, je répéterai mon affirmation qu'une expression lambda n'est pas du sucre syntaxique pour une classe interne anonyme. Ratchet freak a déclaré qu'une expression lambda est traduite en une instanciation de classe interne anonyme, et Sparkleshy a simplement réaffirmé qu'un lambda est du sucre syntaxique pour une classe interne anonyme, mais ces déclarations sont incorrectes. Ils sont probablement basés sur des informations obsolètes. Les premières implémentations lambda ont effectivement implémenté lambdas de cette façon, mais les choses ont changé.

Les expressions lambda sont sémantiquement différentes des classes internes et sont implémentées différemment des classes internes.

Les expressions lambda sont sémantiquement différentes des classes internes de deux manières. L'évaluation d'une expression lambda n'a pas besoin de créer une nouvelle instance à chaque fois. Ils ont également des sémantiques de capture différentes, par exemple, ils capturent cela différemment. Dans une classe interne, il s'agit de l'instance de classe interne, tandis que dans une lambda, il s'agit de l'instance englobante. Considérer ce qui suit:

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

Dans une construction lambda JDK 8 récente (j'ai utilisé b69 ), la sortie sera quelque chose comme ceci:

CaptureThis$1@113de03
outer

De plus, les expressions lambda sont implémentées complètement différemment des classes internes. Si vous comparez la sortie désassemblée, vous verrez que le code de la classe interne se compile directement à la création et appelle un constructeur de CaptureThis $ 1, tandis que l'expression lambda se compile en une instruction dynamique invoquée qui fournit un Runnable par des moyens non spécifiés. Pour une explication complète de la façon dont cela fonctionne et pourquoi, voir le discours de Brian Goetz sur JavaOne 2012 Lambda: A Peek Under The Hood .

Stuart Marks
la source
2
"ils capturent cela différemment. Dans une classe interne, c'est l'instance de classe interne, alors que dans un lambda, c'est l'instance englobante. Considérez ce qui suit:" il est toujours possible de faire avec du sucre syntaxique en remplaçant tout thisparMyClass.this
ratchet freak
4
Tout ce qui va au-delà de l'assembleur (et parfois même cela) est sans doute du sucre syntaxique. Mais les lambdas ne sont plus du sucre syntaxique pour les classes internes. Ils servent un objectif similaire et ont des similitudes, mais sous le capot, ils sont (de façon observable) différents.
Joachim Sauer
1
"Les expressions lambda sont sémantiquement différentes des classes internes, et elles sont implémentées différemment des classes internes.": Merci pour la très bonne explication (+1). Ce qui n'est pas encore clair pour moi, c'est pourquoi les lambdas n'ont pas été implémentés comme sucre syntaxique pour des classes anonymes spéciales ou, en d'autres termes, quel est l'avantage de la complexité supplémentaire introduite par la nouvelle sémantique? Quel problème cela résout-il qui ne peut pas être résolu avec des classes internes anonymes? (Mais je dois encore regarder le lien que vous avez posté, peut-être y trouverai-je la réponse.)
Giorgio
1
@Joachim Sauer: Je considérerais le sucre syntaxique comme une nouvelle syntaxe pour une sémantique existante. Quand une nouvelle sémantique est introduite, je pense que vous ne pouvez pas parler de sucre syntaxique. En ce sens, je ne pense pas que vous puissiez affirmer que tout ce qui dépasse l'assembleur est du sucre syntaxique.
Giorgio
3
@Giorgio: concernant pourquoi lambda n'est pas seulement du sucre syntaxique pour les classes internes anonymes, il s'est avéré qu'il y avait une grande discussion à ce sujet. Ce courrier de Brian Goetz résume la décision: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL; DR il laisse la porte ouverte à une évolution future et nous obtenons de meilleures performances aujourd'hui. Goetz répond en fait à une question connexe: les lambdas sont-ils des objets? Mais si la réponse est non ou même peut-être que cela implique qu'ils ne peuvent pas être du sucre pour les classes internes.
Stuart marque le