Une expression lambda est-elle autre chose qu'une classe interne anonyme avec une seule méthode?

40

Il existe un nouveau battage publicitaire avec les expressions lambda tant attendues dans Java 8; tous les 3 jours, un autre article apparaît avec eux sur leur fraîcheur.

D'après ce que j'ai compris, une expression lambda n'est rien de plus qu'une classe interne anonyme avec une seule méthode (au moins au niveau du code octet). En plus de cela, il comporte une autre inférence intéressante, mais je pense que l’équivalent de cela peut être obtenu avec des génériques à un certain niveau (bien sûr, pas de façon aussi nette qu'avec les expressions lambda).

Sachant cela, les expressions lambda vont-elles apporter quelque chose de plus qu'un simple sucre syntaxique en Java? Puis-je créer des classes plus puissantes et flexibles ou d'autres constructions orientées objet avec des expressions lambda qu'il est impossible de construire avec les fonctionnalités de langage actuelles?

m3th0dman
la source
30
Quand une langue est complète, toutes les fonctionnalités ajoutées peuvent théoriquement être qualifiées de "sucre syntaxique".
Philipp
34
@ Philippe: C'est faux. La caractéristique déterminante du sucre syntaxique est que le desugaring est purement local et ne change pas la structure globale du programme. Il y a beaucoup de fonctionnalités qui ne peuvent pas être implémentées avec juste des transformations locales. Par exemple, si vous prenez un langage hypothétique identique à Java mais avec des appels de queue appropriés, il ne sera pas possible de désactiver les appels de queue en Java "pur" sans transformer globalement l'ensemble du programme.
Jörg W Mittag
2
@Philipp: Malheureusement, il n'y a qu'un seul vote positif pour les commentaires, sinon je voterais 1000 fois plus que le commentaire de Joerg. Non, il est faux que toute caractéristique puisse être qualifiée de sucre syntaxique. Le sucre syntaxique n'ajoute pas de nouvelle sémantique. En fait, autant que je sache, les lambdas Java proposés ne sont PAS un sucre syntaxique pour les classes internes anonymes spéciales, car ils ont une sémantique différente.
Giorgio
1
@Giorgio: et quelles sont leurs différentes sémantiques?
user102008
2
@Giorgio: Oui, mais la conversion de thisen OuterClass.thisfait partie du processus de décomposition des expressions lambda en classe anonyme.
user102008

Réponses:

47

tl; dr: bien qu’il s’agisse principalement de sucre syntaxique, cette syntaxe plus élégante rend pratique beaucoup de choses qui se terminaient par des lignes infinies et illisibles d’accolades et de parenthèses.

Eh bien, c’est en fait l’inverse, les lambdas sont beaucoup plus âgés que Java. Les classes internes anonymes avec une seule méthode sont (étaient) les Java les plus proches de lambdas. C'est une approximation qui était "assez bonne" pendant un certain temps, mais dont la syntaxe est très désagréable.

En surface, les lambdas de Java 8 ne semblent pas être beaucoup plus que du sucre syntaxique, mais lorsque vous regardez sous la surface, vous voyez des tonnes d'abstractions intéressantes. Par exemple, la spécification JVM traite un lambda de manière tout à fait différente d'un objet "vrai" et, bien que vous puissiez les gérer comme s'ils étaient des objets, la JVM n'est pas obligée de les implémenter en tant que tels.

Mais si toute cette ruse technique est intéressante et pertinente (car elle permet d’optimiser la future machine virtuelle!), Le vrai avantage est "juste" la partie sucre syntaxique.

Quoi de plus facile à lire:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

ou:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

ou (en utilisant un handle de méthode au lieu d'un lambda):

myCollection.map(String::toUpperCase);

Le fait que vous puissiez enfin exprimer de manière concise ce qui serait auparavant 5 lignes de code (dont 3 totalement ennuyeuses) apporte un réel changement de ce qui est pratique (mais pas de ce qui est possible, bien sûr).

Joachim Sauer
la source
1
Je suis totalement d'accord avec la partie syntaxe sucre. Ma question portait sur les nouvelles constructions orientées objet uniquement possibles avec les expressions lambda. après tout, Java est un langage orienté objet. Pensez par rapport aux génériques, et comment ils ont acheté beaucoup de flexibilité en Java, une flexibilité impossible à obtenir sans eux.
m3th0dman
7
@ m3th0dman: en réalité, les génériques n'ont ajouté aucune nouvelle capacité. Un Listpeut contenir n'importe quel objet, un List<String>peut "seulement" contenir des chaînes. Les génériques ont ajouté une restriction (et l'option de formaliser les restrictions!), Pas un ajout de pouvoir. Presque tout depuis Java 1.1 est du sucre syntaxique. Et ce n'est pas nécessairement une mauvaise chose.
Joachim Sauer
3
@ m3th0dman: En réalité, les génériques n'ont ajouté aucune nouvelle capacité car, en Java, ils ne sont qu'un sucre syntaxique. A List<String>est juste un Listatout à Stringajouter autour de certaines valeurs de retour. Néanmoins, ils sont extrêmement utiles et rendent le langage beaucoup plus pratique à écrire. Les Lambdas sont un cas similaire.
Jan Hudec
3
En réalité, il s’agit bien plus que du sucre syntaxique. Une grande partie de la fonctionnalité est implémentée en tant que citoyen de première classe dans la machine virtuelle via l’utilisation du bytecode invokedynamic + de très importantes avancées vers le système d’inférence de type. Ce n'est pas implémenté en tant que classes internes anonymes.
Martijn Verburg
1
@JanHudec: eh bien, ils sont légèrement plus que du sucre syntaxique, car le compilateur les respecte. Le runtime s'en fiche, c'est vrai.
Joachim Sauer
14

Pour Java, oui, il n’ya rien de mieux qu’un meilleur moyen de créer une classe interne anonyme. Ceci est dû à la décision fondamentale en Java que chaque bit de code octet doit vivre dans une classe spécifique, qui ne peut plus être modifiée maintenant, après des décennies de code hérité à prendre en compte.

Cependant, ce n’est pas ce que les expressions lambda sont vraiment. Dans les formalismes où il s’agit de concepts natifs plutôt que de contorsions, les lambdas sont des éléments fondamentaux; leur syntaxe et l'attitude des gens à leur égard sont très différentes. L'exemple d'une fonction récursive anonyme créée purement à partir de lambdas dans Structure et interprétation des programmes informatiques est capable de changer toute votre conception du calcul. (Cependant, je suis à peu près sûr que cette façon d'apprendre à programmer est juste pour devenir un cas de réussite traditionnel.)

Kilian Foth
la source
1
Apprendre que tout peut être mis en œuvre en termes de lambdas est très instructif et pas "ésotérique" à mon avis. (Cependant, je suppose que la plupart des "codeurs" ne se soucient pas de la théorie intéressante de CS.) Cela ne signifie pas que lambdas est spécial; cela signifie simplement que les lambdas sont un type de construction universelle. Il y en a d'autres, comme les combinateurs de ski. Les lambda sont des éléments fondamentaux dans les paradigmes fonctionnels, mais peut-être que quelque chose d'autre peut être fondamental dans un autre paradigme.
user102008
+1 pour "la contorsion": je me demande souvent pourquoi certaines langues ne cessent de changer pour imiter d'autres langues populaires et pourquoi les programmeurs l'acceptent. J'aime beaucoup les lambdas et les utilise beaucoup en scala, lisp, hakell, mais en java ou en c ++, ils se sentent comme une réflexion après coup collée à la langue simplement parce qu'ils sont devenus populaires dans d'autres langues.
Giorgio
2

Oui, il ne s'agit que d'un sucre syntaxique, dans le sens où vous écrivez un lambda, vous pouvez réécrire cette expression en tant qu'expression de classe interne anonyme avec une méthode, où la classe implémente l'interface fonctionnelle inférée pour le contexte du lambda, et ce serait exactement équivalent sémantiquement. Et vous pouvez le faire en remplaçant simplement l'expression lambda par l'expression de classe anonyme, sans modifier aucune autre expression ou ligne de code.

utilisateur102008
la source
1
pourquoi downvote? ce que j'ai dit est tout à fait correct
user102008
Ce que vous écrivez semble une proposition raisonnable pour les lambdas Java, mais cette proposition a été écartée au profit d’une autre ( doanduyhai.wordpress.com/2012/07/12/… ).
Giorgio
1
@Giorgio: Je ne "propose" rien. En quoi es-tu exactement en désaccord avec ce que j'ai dit? Oui, l'intérieur de l'expression sera différent, par exemple nous allons ajouter une méthode et oui, thisil faudra convertir OuterClass.this. Cela ne contredit pas ce que j'ai dit - chaque expression lambda peut être convertie en une expression de classe anonyme sémantiquement équivalente sans modifier quoi que ce soit en dehors de cette expression . Je n'ai pas dit que l'intérieur ne changerait pas.
user102008
3
Ce que tu as dit est incorrect. La sémantique des classes internes lambda et anon n'est pas exactement la même (bien qu'elles soient similaires). De mémoire, le sens du mot ceci change; et anon classes internes résultent toujours dans une nouvelle instance d'un objet, alors qu'un lambda pourrait ou non.
Stuart Marks
1
@StuartMarks: Non, vous n'avez pas lu ma réponse. Je n'ai pas dit que chacun d'entre eux peut faire tout ce que l'autre fait. J'ai dit qu'un lambda a une classe anonyme équivalente qui est sémantiquement identique. Comme je l'ai déjà dit dans les commentaires, thislambda fait partie du sucre syntaxique et ne constitue pas une différence de sémantique. Et à propos des différences de mise en œuvre, mise en œuvre! = Sémantique. À propos des différences d'identité d'objet; l'identité de l'objet est extrêmement tangente à la fonctionnalité de lambdas; personne ne vérifie de toute façon l’identité d’objet des classes lambdas / anon car elle n’est pas utile.
user102008
1

Joachim Sauer a déjà fait du bon travail en répondant à votre question, mais il n'a fait que faire allusion à quelque chose que je considère comme important. Les Lambdas n'étant pas des classes, ils ne sont pas non plus compilés en tant que tels. Toutes les classes internes anonymes donnent lieu à la création d'un fichier .class qui doit à son tour être chargé par le chargeur de classe. Par conséquent, utiliser Lambdas ne rend pas seulement votre code plus beau, il réduit également la taille de votre code compilé, l'encombrement mémoire de votre ClassLoader et le temps nécessaire au transfert des bits de votre disque dur.

Christoph Grimmer-Dietrich
la source
-1

Non ils ne sont pas.

Une autre façon de le dire est que les lambdas sont un moyen non objectif, aussi concis soit-il, de réaliser la même chose qu'une classe anonyme ou, à mon avis, une classe intérieure réaliserait de manière orientée objet.

Guido Anselmi
la source
1
La programmation fonctionnelle peut être totalement orthogonale à la programmation orientée objet (voir: Scala et F #). Cela se lit comme l'opinion de quelqu'un qui n'aime tout simplement pas la programmation fonctionnelle par principe.
KChaloux
1
@KChaloux - Pas un ennemi de la programmation fonctionnelle. La réponse est écrite par quelqu'un qui préfère avoir un marteau ET un tournevis plutôt qu'un marteau perforateur. La programmation OO est un bon paradigme, de même que la programmation fonctionnelle. Ma préférence dans une langue est de préciser ses intentions. Lambdas, je me sens boueux face à la nature OO de Java. Java n'a pas été conçu pour être un langage fonctionnel. Les êtres humains ont besoin de structure pour faire de leur mieux.
Guido Anselmi