Quels sont les avantages et les inconvénients des approches de C #, Java et Scala to Closures / Lambdas /…?

30

Je me demande quelles sont les différences de mise en œuvre technique entre C # et Scala et comment les deux solutions se comparent aux idées et préoccupations de mise en œuvre exprimées dans l'e-mail Peek Past lambda de Brian Goetz, envoyé à la liste de diffusion du projet Lambda (JSR 335) ?

De l'email:

Nous avons exploré la voie «peut-être que les lambdas ne devraient être que des instances de classe interne, ce serait vraiment simple», mais nous sommes finalement arrivés à la position «les fonctions sont une meilleure direction pour l'avenir du langage».

et plus loin:

La vision lambdas-are-objets du monde est en conflit avec ce futur possible. La vision lambdas-are-functions du monde ne le fait pas, et la préservation de cette flexibilité est l'un des points en faveur de ne pas surcharger les lambdas avec même l'apparence d'objectivité.

Conclusion:

Lambdas-are-functions ouvre des portes. Lambdas-are-objects les ferme.
Nous préférons voir ces portes ouvertes.

Et certains commentaires d'une personne sur le fil Reddit disent:

En fait, j'ai envoyé un courriel à Neal Gafter à ce sujet et à ma compréhension limitée de son explication, C # et la conception Java actuelle sont assez similaires en ce sens que les délégués sont en fait des objets et non des types de fonctions. Il semble qu'il pense que Java devrait apprendre des inconvénients des lambdas de C # et les éviter (un peu comme C # a appris des inconvénients de Java et les a évités au début).

Pourquoi l'approche "Lambdas-are-functions" ouvre-t-elle davantage de possibilités à l'avenir que "Lambdas-are-objects"? Quelqu'un peut-il expliquer quelles différences existent et comment elles influenceraient la façon dont le code serait écrit?

Voyant que les choses dans Scala "fonctionnent juste", je continue de penser que je manque quelque chose au sujet des approches adoptées / proposées en C # / Java (8), probablement est-ce lié à des préoccupations concernant la rétrocompatibilité?

soc
la source
1
C'est intéressant. Étant donné que le système de type Javas n'a pas de concept de fonctions pour l'instant, cela signifierait qu'il faudrait d'abord l'introduire. Il pourrait être possible que le langage devienne trop complexe avec cela.
Ingo
Les fonctions ne devraient-elles pas être des instances d'une interface? Qu'est-ce qui est si spécial à leur sujet?
soc
Lisp / Scheme / Clojure peut modéliser des objets tandis que Java / C # ne peut pas modéliser l'imbrication arbitraire de fonctions. Python semble cependant avoir le meilleur des deux mondes.
Job

Réponses:

15

Je pense que la discussion concernant les objets par rapport aux fonctions est un hareng rouge. Si la question est: "Un lambda est-il une fonction ou un objet?" la réponse devrait être oui .

C'est le point des fonctions de première classe: elles ne sont pas traitées différemment de tout autre type. Java parvient déjà à ignorer la plupart des différences entre les types Object et primitifs (et Scala fait encore mieux), donc si un lambda est une sous-classe d'Object ou est un nouveau type primitif ou autre chose n'est pas vraiment important pour le langage. Ce qui est important, c'est que vous pouvez mettre vos lambdas dans des collections, les transmettre pour être appelés, les appeler et faire tout ce que vous voudrez faire avec un objet ou une méthode.

Scala accomplit cela en utilisant un objet wrapper qui a une méthode appelée applyqui peut être invoquée avec just (), ce qui la fait ressembler à un appel de méthode. Cela fonctionne à merveille; la plupart du temps, vous n'avez même pas besoin de vous soucier de savoir si vous avez une méthode ou si vous appelez l'application d'un objet fonction.

Rex Kerr
la source
9

D'après ce que je comprends, il s'agit davantage de la façon dont les lambdas sont considérés au niveau de la langue principale. Comme le dit l'e-mail,

Vous pourriez penser que la conception actuelle est étroitement liée à une boîte d'objets pour les lambdas - types SAM - ce qui en fait de toute façon des objets efficaces. Mais cela a été soigneusement caché de la surface afin de nous permettre de considérer les lambdas «nus» à l'avenir, ou d'envisager d'autres contextes de conversion pour les lambdas, ou d'intégrer plus étroitement les lambdas dans les constructions de contrôle. Nous ne le faisons pas maintenant, et nous n'avons même pas de plan concret pour le faire, mais la possibilité de le faire à l'avenir est un élément essentiel de la conception.

Je pense que cela résume très bien votre question. Si vous déclarez que "les lambdas sont des objets", alors ils ne sont qu'un objet d'une classe particulière et vous êtes coincé avec cela. D'un autre côté, si vous déclarez que "les lambdas sont des fonctions", alors sémantiquement vous avez un terrain de jeu beaucoup plus riche. Java 1.7 peut les compiler en objets, ils sont donc pratiquement identiques à ce stade.

Mais Java 1.8, ou 1.9, pourrait apporter des changements au langage (tels que des types structurels réifiés) que permettre aux fonctions d'être utilisées de manière beaucoup plus flexible. Si "les lambdas étaient des objets", ces changements ne seraient pas rétrocompatibles et il faudrait introduire un nouveau concept au total, afin de ne pas casser le code existant des gens. Mais si javacje convertissais simplement des lambdas en objets en coulisses, le nouveau javacpeut les convertir en tout ce qu'il veut, tant que la sémantique tient toujours.

Andrzej Doyle
la source
lamdas en C #! = des délégués. Le compilateur a la possibilité de les compiler dans des arborescences de délégué ou d'expression. les deux sont en effet des graphes d'objets mais ils ne sont pas compilés dans une "classe particulière" ni même une classe d'un arbre d'héritage particulier
Rune FS
Si je comprends bien, alors la compilation du lambda dans une classe interne de l'objet qui lui est associé le lie à cet objet, donc à l'avenir si Java devait introduire des fonctions d'ordre supérieur (fonctions au même niveau d'objets), alors vous ne pouvait pas utiliser l'implémentation de classe interne et il y aurait une incohérence. Je ne pense pas que Java aura bientôt des fonctions de niveau supérieur.
mwolfetech
@mwolfetech: Pour autant que je sache, ils sont déjà prévus pour Java 8 avec des méthodes de défense. Ils veulent ajouter des choses comme foreach, map, filteraux collections.
soc
@soc Bon point, il est difficile de suivre le nombre de JSR et de savoir s'ils vont réellement terminer et créer une version cible du JDK. Il semble que les méthodes de défenseur puissent faire partie du même JSR. En ce qui concerne ce JSR , j'ai trouvé l'article de Brian Goetz sur l' état de Lambda utile - explique les types SAM et les réflexions actuelles sur la mise en œuvre des expressions lambda.
mwolfetech
"pensées actuelles" mhhh, ce billet de 2010 n'est-il pas obsolète maintenant?
soc
5

Surtout, il ne veut tout simplement pas s'engager trop tôt dans quelque chose. Je ne vois aucune raison au-delà de l'effacement qu'il a présenté, mais c'est vraiment une raison très forte.

Je n'aime pas les types de fonctions - j'adore les types de fonctions - mais ces types de fonctions se sont mal battus avec un aspect existant du système de types Java, l'effacement. Les types de fonctions effacées sont les pires des deux mondes.

Considérez ces méthodes dans Scala Regex:

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

Ce serait plus simple s'ils étaient simplement ceci:

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

Malheureusement, ce n'est pas possible, car ces deux fonctions sont identiques à l'effacement. Mais, très bien, ces fonctions font des choses quelque peu différentes, donc un nom différent pourrait être assez juste.

Cependant, a Matchest quelque chose de très utile, mais la plupart du temps vous voulez soit la correspondance, Stringsoit la liste des sous-groupes. Nous aimerions avoir ceci:

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

Pas possible, à cause de l'effacement. J'ai choisi cet exemple particulier parce que j'y étais directement impliqué, mais j'ai vu au moins une demi-douzaine de questions sur Stack Overflow, où les gens demandent pourquoi une surcharge est illégale, causée par ce problème exact.

Et puis, considérez que la mise en correspondance des motifs de Scala et celle de Java instanceofsont effectivement inutiles à cause de l'effacement.

Je pense qu'il est juste de retarder les types de fonctions jusqu'à ce que ce problème soit réglé. Après tout, il existe de nombreux langages sur la JVM, et ce n'est pas comme si Java était un langage en évolution rapide.

Daniel C. Sobral
la source
Eh bien, si l'effacement de type est le seul problème qu'ils ont, que prévoient-ils faire? Briser tous les codes de cette planète était déjà considéré comme une non-option pour Java 5 ...
soc
@soc Je suis tellement content de ne pas être à leur place! Mais c'était Sun, c'est Oracle. Oracle n'a jamais eu la moindre difficulté à effectuer des changements de rupture entre les versions majeures - et même mineures - de son produit principal.
Daniel C.Sobral
Peut-être qu'ils devraient changer le nom de la langue et commencer à développer une nouvelle langue, en supprimant la compatibilité descendante. On aurait donc les avantages d'une nouvelle langue sans avoir à jouer avec une langue plus ancienne et bien établie. Après tout, c'est ce que Scala et Clojure ont fait.
Giorgio
@Giorgio Ce serait un peu inutile. Eh bien, certaines des personnes responsables de ce qu'est Java aujourd'hui l'ont fait, mais, comme vous l'avez dit, il existe des alternatives. Mais les responsables de Java doivent améliorer Java lui-même - ils en sont responsables , après tout. La seule alternative est de simplement abandonner Java et de renoncer à tous les avantages résultant de son contrôle.
Daniel
@Daniel C. Sobral: IMO un langage de programmation est un peu comme un logiciel: au début, il peut être propre et bien conçu mais plus vous jouez avec, plus il devient désordonné. Je pense donc qu'il serait dans l'intérêt des développeurs de geler Java en tant que langage et de concentrer le développement sur (1) la création de nouvelles bibliothèques ou l'amélioration des bibliothèques existantes, (2) l'amélioration de la JVM (si possible), (3) le développement de nouveaux langages . Mais comme vous l'avez dit, il y a des gens qui sont responsables de Java et qui veulent continuer à vendre des mises à niveau. Ils vont donc l'étendre pour le garder "cool". Juste mes 2 cents.
Giorgio