août
2011
Petit à petit le projet Lambda suit son cours, et le brouillon des spécifications comment à bien s’étoffer.
En fin de semaine dernière, Alex Buckley a publié une nouvelle version de ce brouillon dans la mailling-list, que l’on peut retrouver ici : Project Lambda: Java Language Specification draft version 0.1.5.
S’en est suivi plusieurs discussions, dont un débat sur la syntaxe d’appel d’une expression lambda.
Prenons une expression lambda définie de la manière suivante :
#int(int) doubler = #(int x)(x + x);
Cette expression se contente de renvoyer le double d’un nombre.
Mais comme utilisera-t-on cette expression ?
L’approche la plus « lisible » aurait été de considérer les expressions lambda comme des méthodes, en permettant de les appeler directement avec une syntaxe de ce genre :
int value = doubler(5);
Mais cela pose de gros problème de résolution de méthode. En effet cela augmente le risque de conflit de nom avec une méthode existante. L’appel d’une expression lambda pourrait remplacé involontairement l’appel d’une méthode static ou d’instance, et apporter ainsi beaucoup d’ambiguïté tout en complexifiant le travail du compilateur. Sans compter les risques d’incompatibilités futur…
Dans un premier temps, une solution simple et efficace envisagé pour éviter ce problème était de considérer les expressions lambda comme des objets qui, par convention, contiendrait une méthode nommée invoke(). Ce qui permettait de les utiliser comme un objet quelconque :
int value = doubler.invoke(5);
C’est plus verbeux mais cela permet d’éviter toute ambiguïté pour le compilateur.
Toutefois cette solution ne fait pas l’unanimité. D’une part du fait de sa verbosité, alors que l’objectif des expressions lambda est bien de réduire cela. D’autre part car cela considère que les expressions lambda sont des objets, alors que ce n’est pas forcément le cas. Conceptuellement il s’agit d’une méthode anonyme, et il n’y a pas de raison de lui donner un nom !
Aujourd’hui, la solution envisagée se rapproche beaucoup de la toute première approche, mais en utilisant un nouvel opérateur pour distinguer l’appel d’une expression lambda de l’appel d’une méthode standard.
Comme les expressions lambda sont des méthodes anonymes, le nom de la méthode a été supprimé, mais on conserve le « point » afin de les distinguer des appels de méthodes :
int value = doubler.(5);
A première vue cela choque un peu. On dirait presque une erreur de syntaxe…
Je suppose qu’il faudra s’y habituer !
18 Commentaires + Ajouter un commentaire
Tutoriels
Discussions
- [REFLEXION] Connaitre toutes les classes qui implémentent une interface
- L'apparition du mot-clé const est-il prévu dans une version à venir du JDK?
- Recuperation du nom des parametres
- Difference de performances Unix/Windows d'un programme?
- [ fuite ] memoire
- Possibilité d'accéder au type générique en runtime
- Classes, méthodes private
- jre 1.5, tomcat 6.0 et multi processeurs
- Définition exacte de @Override
[…] les Lambda, ce ne sont pas les articles qui manquent sur les blogs comme Developpez.com (ici ou ici) ou les talks dans les JUG. Bref, je n’étais pas un terrain conquis dès le départ, loin de […]
Mais le pire c’est que « λdoubler » est un nom de méthode valide pour le compilateur
a++
bien alors: λdoubler(6) ! appelons une lambda avec un lambda
La compatibilité des sources n’est pas garantie, mais l’objectif est d’éviter de multiplier les incompatibilités
a++
Certes Java ne garantit déjà pas la compatibilité des sources vers les versions supérieures.
Syntaxiquement c’est inhabituelle oui ! Quoique si on regarde bien cela correspond à l’appel d’une méthode sans nom…
Mais je suis d’accord que le fait d’utiliser un nom de méthode fixé par convention serait bien moins « choquant ».
a++
int value = doubler.(5); ca va totalement a l’encontre de la lisibilité habituelle de java.
changer de comportement pour juste un ‘.’ pas trop visible … sic
Pourquoi ?
Ca fait pas très « objet » comme principe
L’intérêt est de pouvoir manipuler des références vers des méthodes, et donc de passer ces méthodes en paramètre d’autre méthode ou de les conserver pour les exécuter plus tard.
Actuellement pour faire cela on a deux choix :
L’intérêt des expressions lambda c’est une syntaxe légère et peu verbeuse, et une plus grande souplesse du fait de la covariance. En fait tu peux affecter des expressions lambda avec des signatures différentes tant qu’il y a une certaine compatibilité, là où tu es très limité avec les classes anonymes…
a++
C’est quoi l’intérêt de ces expressions Lambdas ?
Pourquoi ne pas simplement définir une fonction doubler() qui fait la même chose ?
Je n’aime pas la direction que prend Java, on dirait qu’il veut ressembler à un mélange C/C++
@Uther : Le problème c’est que tu peux écrire un code sans conflit ni erreur, mais qui rencontre le problème dans une version future à cause d’une évolution de l’API par exemple.
Dans ce cas cela pose un problème du point de vue de la compatibilité des sources, puisque ton code qui compilait parfaitement ne compile plus…
Perso je suis plutôt partisan d’une syntaxe d’appel différente de celle des méthodes pour plus de clarté. Mais en ce qui concerne la syntaxe exacte je n’ai pas vraiment d’avis…
semble intéressant, mais ressemble fortement aux « method reference » (quoique le brouillon des specs n’en parle toujours pas – j’espère que c’est toujours d’actualité).
a++
Je serais surpris que ce genre de chose arrive tous les jour.
Pourquoi ne pas en faire un cas d’erreur?
#doubler(5) me parait pas trop mal non plus étant donné la syntaxe pour la définition de la méthode lambda.
Et si on a une expression lambda nommé « doubler » en attribut, this.doubler() appelle-t-il la méthode doubler() ou l’expression lambda doubler() ? Comment les différencier dans ce cas là ?
Tu le dit toi-même dans certain cas une méthode peut-être masqué, donc il y a des conflit potentiel. Il n’y a rien d’insurmontable en soit mais il y a toujours un risque de problème de compatibilité future à cause de cela…
Ce genre de problème existe déjà entre les méthodes, même sans les expressions lambda, mais ils sont plus limité. L’objectif étant de ne pas accroitre ce genre de problème.
a++
comme la dernière ce serait top :
#doubler(5);
$doubler(5);
%doubler(5);
@doubler(5);
&doubler(5);
*doubler(5);
…
En C#, une lambda est appelée comme une méthode.
Si la lambda a une signature identique à une méthode de la classe, cette dernière a sa visibilité masquée (comme si une variable d’une méthode masque la visibilité d’un membre portant le même nom).
Tout ceci n’empêche pas le « this.doubler() » si on veut appeler la méthode existante.
Bref, je pense que si en C# il n’y a pas de problème avec les conflits, pourquoi y en aurait-il en Java?
Ceci dit, pour bien différencier les méthodes et les lambdas, sans syntaxe verbeuse, pourquoi ne pas remplacer l’opérateur « d’exécution de fonction » à savoir ‘()’ ?
Cela donnerai:
// méthode existante:
doubler(5);
// lambda ?
doubler[5]; // conflit avec un tableau existant?
doubler{5};
doubler;
doubler|5|;
…
#doubler(5); ?
Je pense vraiment que les nouveautés de java 7 peuvent apporter un plus, mais je trouve que les choix syntaxiques sont souvent plus que douteux !
La dernière solution ressemble vraiment a une erreur de syntaxe et il est certain qu’un développeur passera derrière pour essayer de la corriger en pensant bien faire, d’ou une perte de productivité et de lisibilité.
Je préférerais un opérateur devant l’expression indiquant au compilateur et aux développeurs qu’il s’agit d’une expression lambda.
Dans tous les cas, merci de nous faire partager tes recherches