août
2006
J’ai lu l’article sur les « closures » mentionné par adiguba sur son blog. J’ai également regardé ces exemples, et je dois dire que je suis désolé, mais je n’aime pas du tout la syntaxe qui a été choisie, ni la direction que cela prend.
Veillez d’abord lire ce ‘disclaimer’ avant de lire le reste de l’article.
Tout d’abord, veuillez me pardonner si cet article est remplis d’erreurs.
Il est tout à fait possible, et même probable, que je n’ai encore rien compris à ce qu’était les « closures ».
Si telle était le cas, pourriez-vous prendre la peine de me le ré-expliquer. Je sais qu’adiguba a déjà essayé. Mais je ne pense pas avoir vraiment tout saisi.
Si je me suis completement trompé, cela me ferait plaisir que quelqu’un me le ré-explique encore une fois. Et là, je lance un appel à Romain Guy. Pourrais-tu nous faire un article sur ce sujet ? Après cela, je suis sûr que j’aurai vraiment tout compris.
Reprenons le 1er exemple du PDF (un exemple de fonction locale):
public static void main(String[] args) { <br />
int plus2(int x) { return x+2; } <br />
int(int) plus2b = plus2; <br />
System.out.println(plus2b(2)); <br />
} <br />
A quoi sert la 2ième ligne ? Pour moi, elle ne sert à rien.
Tant qu’à faire, je préfererais écrire quelque chose comme ceci
public static void main(String[] args) { <br />
int plus2(int x) { return x+2; } <br />
System.out.println(plus2(2)); <br />
} <br />
Ca, ça me parait plus clair. Pas vraiment de nouvelle syntaxe introduite. C’est juste qu’on permet la déclaration de méthodes dans une méthode.
Tout comme avant on pouvait avoir des variables locales, on pourra maintenant avoir des méthodes locales.
Et on pourrait même imaginer qu’on puisse écrire le code suivant:
public class Closure { <br />
private static y = 10; <br />
private static int plus2b(int x) {return x+2;} //déclare méthode static <br />
<br />
public static void main(String... args) { <br />
//déclaration de ma méthode locale <br />
int plus2b(int x) {return x+4;} <br />
int y = 5; <br />
<br />
//Exemple1 <br />
//utilisation de la méthode locale avec la variable locale <br />
// > affichera 9 <br />
System.out.println(plus2b(y)); <br />
<br />
//Exemple2 <br />
//utilisation de la méthode de class avec la variable locale <br />
// > affichera 7 <br />
System.out.println(this.plus2b(y)); <br />
<br />
//Exemple3 <br />
//utilisation de la méthode locale avec la variable de classe <br />
// > affichera 14 <br />
System.out.println(plus2b(this.y)); <br />
<br />
//Exemple4 <br />
//utilisation de la méthode de classe avec la variable de classe <br />
// > affichera 12 <br />
System.out.println(this.plus2b(this.y)); <br />
} <br />
} <br />
Ce qui me paraît un comportement normal. On fait des déclarations de méthodes locales, comme on fait des déclarations de variables locales. Et les méthodes locales ont priorités sur les méthodes d’instance ou statique, tout comme les variables locales ont priorités sur les variables d’instance ou statique.
Et je trouve cela bien plus élégant et bien plus lisible. Et pas de nouvelle syntaxe à inventer.
Maintenant, poussons plus loin, et voyons ce que cela donnerait avec des méthodes locales anonymes (ce qu’ils appellent des « closures » ou encore « fonctions anonymes » dans leur document):
Qu’est ce que cela donnerait avec des méthodes anonymes ?
public class Closure { <br />
private static y = 10; //déclaration variable de classe <br />
private static int plus2b(int x) {return x+2;} //déclaration méthode de classe <br />
<br />
public static void main(String... args) { <br />
//déclaration méthode locale <br />
int plus2b(int x) {return x+4;} <br />
//déclaration variable locale <br />
int y = 5; <br />
<br />
//utilisation d'une méthode anonyme <br />
// > affichera 9 <br />
System.out.println((int y) {return y+4;)); <br />
<br />
//utilisation d'une autre méthode anonyme <br />
// > affichera 15 <br />
System.out.println((int y) {return y+this.y;}); <br />
<br />
//Cette écriture ci n'a pas de sens, ne devrait même pas compiler <br />
System.out.println((int this.y) {return this.y+5;}); <br />
<br />
//on devrait plutôt l'écrire comme ceci <br />
// > affichera 14 <br />
System.out.println(() {return this.y+5;}); //methode anonyme sans argument <br />
<br />
//Et maintenant le truc de la mort <br />
//la méthode anonyme qui appelle la méthode locale <br />
System.out.println((int y) (return plus2b(y);}); <br />
//la méthode anonyme qui appelle la méthode de classe <br />
System.out.println((int y) (return this.plus2b(y);}); <br />
} <br />
} <br />
Concernant la syntaxe raccourcie, je pense qu’elle n’a pas du tout son utilité. Et qu’on ne devrait surtout pas l’utiliser.
Bien souvent, on considère ceci :
if (condition_complexe) <br />
//fait quelque chose; <br />
else <br />
//fait autre chose; <br />
//le code continue;
comme étant une mauvaise pratique. Le 1er qui fait cela dans mon équipe, je me fache tout rouge.
C’est bien plus préférable ceci:
if (condition_complexe) { <br />
//fait quelque chose; <br />
} <br />
else { <br />
//fait autre chose; <br />
} <br />
//le code continue;
Et bien, j’ai envie de dire que c’est ce qui va se passer pour la forme raccourcie des closures. L’expérience va nous démontrer que cela va être une mauvaise pratique.
Mais le pire est encore à venir:
Si vous exécutez le code suivant:
public static void main(String[] args) { <br />
System.out.println(5/0); <br />
} <br />
Vous obtiendrez une ArithmeticException: / by zero
Si vous exécutez le code suivant:
public static void main(String[] args) { <br />
int divPar0(int x) { return x/0; } <br />
System.out.println(divPar0(5)); <br />
} <br />
Vous obtiendrez, si j’ai bien compris leur document, également une ArithmeticException: / by zero
Par contre, en utilisant la syntaxe raccourcie (telle que décrite par le document)
public static void main(String[] args) { <br />
int divPar0 = (int x) : x/0; <br />
System.out.println(divPar0(5)); <br />
} <br />
cela afficherait null
Et là, je ne suis plus d’accord. Que le type de syntaxe utilisée influence le résultat, n’est vraiment pas une bonne idée. Qu’on n’appele pas cela alors une syntaxe raccourcie. Une « syntaxe raccourcie » qui a pour conséquence un autre comportement que la « syntaxe verbeuse ».
De plus, on en vient quelque peu à des situations un peu louffoque:
(j’utilise ici leur syntaxe)
public static void main(String[] args) { <br />
int(int) divPar0 = (int x) : x/0; <br />
int(int) longDivPar0 = (int x) {return x/0); <br />
Integer i = null; <br />
int j = i; <br />
int k = divPar0(5); <br />
int l = longDivPar0(5); <br />
System.out.println(i); //1 afficherait null. <br />
System.out.println(j); //2 afficherait 0. <br />
System.out.println(k); //3 afficherait null. <br />
System.out.println(l); //4 provoquerait une exception. <br />
<br />
} <br />
Notez le résultat de la ligne 3. Ca afficherait null. Car k, de type int, c’est à dire un type primitif pourrait avoir comme ‘valeur’ null.
Si les types primitifs peuvent maintenant avoir comme valeur ‘null’, pourquoi est ce que la ligne 2 n’afficherait pas également ‘null’ ? Parce qu’il faut être compatible avec le JDK 5.0.
Pourquoi alors n’ont-ils pas transformé le null en type dans le JDK 5.0 ? Apparemment, ils n’y ont pas pensé, ou n’ont pas voulu le faire.
Aargh, j’en ai marre de cette syntaxe.
[edit 26/8/2006 20h40]Une bonne nouvelle tout de même. C’est que Gafter le reconnait dans son dernier billet sur son blog . Et ils vont plancher sur une nouvelle proposition.
Le blog de Gafter: http://gafter.blogspot.com/
Son dernier billet: http://gafter.blogspot.com/2006/08/use-cases-for-closures.html
[/edit]
Les autres billets à ce sujet:
http://gafter.blogspot.com/2006/08/closures-for-java.html et
http://gafter.blogspot.com/2006/08/whats-point-of-closures.html
2 Commentaires + Ajouter un commentaire
Commentaires récents
Archives
- janvier 2012
- novembre 2010
- février 2009
- janvier 2009
- décembre 2008
- septembre 2008
- août 2008
- décembre 2007
- octobre 2007
- septembre 2007
- juillet 2007
- mai 2007
- avril 2007
- mars 2007
- février 2007
- janvier 2007
- décembre 2006
- novembre 2006
- octobre 2006
- septembre 2006
- août 2006
- juillet 2006
- juin 2006
- mai 2006
- avril 2006
- février 2006
- janvier 2006
- décembre 2005
- novembre 2005
- octobre 2005
- septembre 2005
- août 2005
- juillet 2005
- juin 2005
- mai 2005
- avril 2005
Catégories
- Certification
- Défis
- Devoxx
- Devoxx 2008
- Devoxx 2010
- Devoxx France 2012
- Divers
- Événements Java
- Fiches
- Hardware
- In English
- Java
- JavaDay 2006
- JavaFX
- JavaOne 2005
- JavaOne 2006
- JavaOne 2007
- Javapolis 2005
- Javapolis 2006
- Javapolis 2007
- JBoss
- Livres
- Mac
- NetBeans
- OpenJDK
- Pensée
- Performance
- Perles
- Sun Tech Days Paris 2007
- Traduction
Pour ce qui est de la différence d’exception selon le type de closure, c’est ce que j’ai compris à la lecture du document. Et il semble que j’avais bien compris, car je viens de voir l’autre billet sur le blog de Neal (http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html)
Est-ce que je me trompe ?
>> A quoi sert la 2ième ligne ? Pour moi, elle ne sert à rien.
Je pense qu’il s’agit juste d’un exemple d’affectation.
Dans le premier cas tu déclares une closures, et dans le second tu affectes la closures dans un variable…
Par contre je ne comprend pas trop ton exemple lorsque tu passes la closures en paramètre de println() :
Pour moi ceci ne devrait pas exécuter la closures, mais appeller sa méthode toString() (puisqu’il s’agit d’un objet).
Pour accepter des closures en paramètre il faudra que les méthodes déclare un paramètre de type closure, par exemple quelque chose du style :
Qui s’utiliserai par exemple de la manière suivante :
Un exemple d’utilisation intérressant que j’ai vu (mais je n’ai plus le lien sous la main), c’est de simuler le mot-clef using du C# (qui permet de libérer une resource à la fin du traitement). Par exemple :
Que l’on pourrait utiliser de la sorte :
Au lieu du traditionnel bloc try/finally :
Par contre je n’ai pas bien compris la raison de la différence d’exception selon le type de closure dans ton exemple ?!?
De plus il y a un problème dans ton exemple :
Sinon je pense vraiment que cela pourrait apporter beaucoup à Java.
a++
PS : intérressant les liens