Suite a notre discussion avec Arkanosis sur le fait que c'etait inutile de
faire :
class A
{
public:
int x() { return x_; }
void x(int x) { x_ = x; }
private:
int x_;
}
car on pouvait ecrire directement :
class A
{
public:
int x;
}
et les deux s'utilisent de la meme facons :
A a;
int b = A.x;
int y = 42;
A.x = y;
// voir http://www.digitalmars.com/d/1.0/property.html
Malgres tout il y a une grosse difference. Le compilateur offre du sucre et le
code compilera toujours si on rajoute un getter/setter par la suite. Mais si
on a publie une libX.so.1.0.0 qui n'avaient pas de getter/setter, le simple
fait de les rajouter engendre un ABI break ce qui entraine une incrementation
du major de la lib : libX.so.2.0.0. Est-ce que vous saisissez le probleme que
je souleve ?
Je veux en venir au fait qu'on ne peut pas changer en cours de route dans le
cas d'une lib que l'on publie. Notre projet n'est pas une lib, mais il est
imaginable que des parties de notre code soient reutilisees pour un
editeur/IDE ou autre. Peut-etre faudrait-il faire des choix stable. Dans le
cadre de l'AST je ne sais pas si c'est vraiment necessaire de faire des
getters/setters. On peut adopter plusieurs politiques :
1) on ne fait pas de getters/setters, on s'en fout de l'ABI car on ne fournit
pas une lib et on se repose sur le sucre syntaxique du D si on veut les
ajouter par la suite. Deplus le code s'executera peut-etre plus vite de cette
maniere.
2) on fait des getters/setters car c'est le moyen sur de ne pas se planter.
Et comme c'est trop chiant de les faires a la main (par ailleur tout ce que
l'on fait a la main est source potentiel de bugs mistiques (copier/colle de
getters/setters...)) on va ecrire un template qui genere le code des
getters/setters. Pof mixin.
Je suis mitige entre la solution 1) et la solution 2). Qu'en pensez-vous ?
En plus de cela il y a des choses que je trouve aberante avec dmd ou le D1.0.
Par exemple le compilateur doit decider par lui meme s'il doit inliner ou non
le code. C'est vraiment debile. Car du code inline n'est pas modifie quand tu
changes la version de la lib (dans le cas du linkage dynamique). Comment peux-
tu savoir que tel partie du code est inline ou non lors de la compilation ? Et
si le compilo inline une fonction virtuelle qu'il ne fallait surtout pas
inliner ? Deplus dmd est cense connaitre la hierarchie et faire de l'appelle
de methode virtuel ou non en analysant la hierarchie des classes. C'est
stupide une fois de plus. Comment tu fais dans le cadre d'un classe loade
dynamiquement ? (Par exemple chess avec les Ai).
J'espere que je me trompe, mais si ce n'est pas le cas je crois qu'on va
implementer un D-custom... :-)
--
Alexandre Bique (bique.a...@gmail.com)
Epita 2009 - Yaka - GISTR
Port. +336 19 42 85 26
Bon, pour le coup de l'incrementation du major de la lib je savais
pas. Mais ce que je peux te dire tout de suite, c'est que la
conclusion a laquelle vous etiez arrives avec Jeremie m'etonne.
Le but des getteurs/setteurs c'est de faire de l'encapsulation. Et
l'interet (en reprenant ton exemple de debut de mail) c'est que le
jour ou tu voudras recuperer la valeur de ton attribut x apres lui
avoir effectue un traitement (supposons qu'il s'agisse d'un salaire
brut et que tu veuilles le recuperer en net) la classe qui sera la
plus facile a modifier c'est celle avec des getteurs/setteurs. La il
est tard et j'ai la flemme d'ecrire un exemple complet montrant la
puissance du principe. Mais je peux t'en pondre de tres jolis si
jamais ça te dit à l'oral.
> [...]
> On peut adopter plusieurs politiques :
> 1) on ne fait pas de getters/setters, on s'en fout de l'ABI car on ne fournit
> pas une lib et on se repose sur le sucre syntaxique du D si on veut les
> ajouter par la suite. Deplus le code s'executera peut-etre plus vite de cette
> maniere.
Non c'est crade.
Dans le cas du developpement d'un projet from scratch je ne pense pas
que vouloir a tout prix optimiser la vitesse d'execution soit vraiment
une idee tres maligne. Il vaut mieux avoir un code modulaire,
uniformement ecrit (getteurs/setteurs partout ou nulle part) pour
aider a la comprehension et a la lecture. Lorsque le projet sera
finit, on pourra se donner a coeur joie dans l'optimisation.
> 2) on fait des getters/setters car c'est le moyen sur de ne pas se planter.
> Et comme c'est trop chiant de les faires a la main (par ailleur tout ce que
> l'on fait a la main est source potentiel de bugs mistiques (copier/colle de
> getters/setters...)) on va ecrire un template qui genere le code des
> getters/setters. Pof mixin.
>
Cette solution est bien meilleure. Par contre je pense que ce n'est
pas interessant d'ecrire un template pour gerer le code des
getters/setters. Car ca peut devenir galere dans le cas ou on devra
modifier certains getters ou certains setters. Le mieux c'est de
configurer ton editeur favori pour avoir une ou deux fonctions de
refactoring comme ont certains IDE. <troll>Sous vim je vois comment
faire, par contre pour emacs ça doit faire un sacre paquet de
parentheses !!!</troll>
> Je suis mitige entre la solution 1) et la solution 2). Qu'en pensez-vous ?
En fin de compte tout depend de la nature de tes attributs. Si tu peux
garantir qu'il n'y a aucune chance pour qu'un jour on prefere acceder
a un attribut autrement qu'en accedant directement a sa valeur, je ne
crois pas que ce soit indispensable (faut pas non plus etre trop
radical, parfois ça peut etre beau de se passer de getters/setters).
Autrement je pense que les getters/setters sont une valeur sure.
>
> En plus de cela il y a des choses que je trouve aberante avec dmd ou le D1.0.
> Par exemple le compilateur doit decider par lui meme s'il doit inliner ou non
> le code. C'est vraiment debile. Car du code inline n'est pas modifie quand tu
> changes la version de la lib (dans le cas du linkage dynamique). Comment peux-
> tu savoir que tel partie du code est inline ou non lors de la compilation ? Et
> si le compilo inline une fonction virtuelle qu'il ne fallait surtout pas
> inliner ? Deplus dmd est cense connaitre la hierarchie et faire de l'appelle
> de methode virtuel ou non en analysant la hierarchie des classes. C'est
> stupide une fois de plus. Comment tu fais dans le cadre d'un classe loade
> dynamiquement ? (Par exemple chess avec les Ai).
>
> J'espere que je me trompe, mais si ce n'est pas le cas je crois qu'on va
> implementer un D-custom... :-)
Ca c'est une autre histoire, et la je suis fatigue donc je vas dormir :)
--
Matías LARRE BORGES
matias.la...@epita.fr
tu peux ecrire
X x = new X();
int a = 42;
X.branle = 42;
L'avais-tu bien saisis ?
Tu peux faire un template qui ne genere que le getter un autre qui ne
genere que le setter et un qui genere les deux. Et niveau relecture
c'est plus rapide de lire un truc du genre :
mixin(Attribute!(Type)("name")); que :
public:
Type name()
{
return name_;
}
void name(Type name)
{
name_ = name;
}
private:
Type name_;
> > Je suis mitige entre la solution 1) et la solution 2). Qu'en pensez-vous ?
> En fin de compte tout depend de la nature de tes attributs. Si tu peux
> garantir qu'il n'y a aucune chance pour qu'un jour on prefere acceder
> a un attribut autrement qu'en accedant directement a sa valeur, je ne
> crois pas que ce soit indispensable (faut pas non plus etre trop
> radical, parfois ça peut etre beau de se passer de getters/setters).
> Autrement je pense que les getters/setters sont une valeur sure.
Niveau relecture/ecriture du code on ne verra pas la difference. C'est
juste une garentie niveau binaire.
> > En plus de cela il y a des choses que je trouve aberante avec dmd ou le D1.0.
> > Par exemple le compilateur doit decider par lui meme s'il doit inliner ou non
> > le code. C'est vraiment debile. Car du code inline n'est pas modifie quand tu
> > changes la version de la lib (dans le cas du linkage dynamique). Comment peux-
> > tu savoir que tel partie du code est inline ou non lors de la compilation ? Et
> > si le compilo inline une fonction virtuelle qu'il ne fallait surtout pas
> > inliner ? Deplus dmd est cense connaitre la hierarchie et faire de l'appelle
> > de methode virtuel ou non en analysant la hierarchie des classes. C'est
> > stupide une fois de plus. Comment tu fais dans le cadre d'un classe loade
> > dynamiquement ? (Par exemple chess avec les Ai).
> >
> > J'espere que je me trompe, mais si ce n'est pas le cas je crois qu'on va
> > implementer un D-custom... :-)
>
> Ca c'est une autre histoire, et la je suis fatigue donc je vas dormir :)
Repose toi bien :-)
--
Alexandre Bique (bique.a...@gmail.com)
Epita 2009 - GISTR - Yaka
> Donc on va vite considerer le fait qu'il faut des getters/setters. La
> question suivante est quelle convention de nomage ?
> Je suis favorable a la notation :
> int salaire(); // getter
> void salaire(int); // setter
Ben c'est la syntaxe des propriétés si je ne m'abuse...
Enfin presque => int salaire(int) // setter
> Daccord/Pas daccord/Suggestion ?
D'accord, vu que ça marche déjà et que quand le compilo le permettra
ce sera déjà des propriétés.
--
Arkanosis
--
Nicolas Ballas
--
Arkanosis
> [...]
> Tu peux faire un template qui ne genere que le getter un autre qui ne
> genere que le setter et un qui genere les deux. Et niveau relecture
> c'est plus rapide de lire un truc du genre :
> mixin(Attribute!(Type)("name")); que :
>
> public:
> Type name()
> {
> return name_;
> }
>
> void name(Type name)
> {
> name_ = name;
> }
>
> private:
> Type name_;
>
Hmmm, non je ne suis nettement pas convaincu par cette approche. A mon
avis les getters/setters faut les écrire en dur meme lorsqu'ils sont
simples (renvoient x ou modifien x sans traitement particulier).
Ca rend les choses plus simples en termes de modification du code.
Mise en situation:
Quelqu'un est en train de déboguer ton code. Dans le cas ou les
getters/setters sont écrits explicitement dans le source-code il se
rendra vite compte que dans ton setter tu ne vérifies jamais que x est
non null ou qu'il verifie une propriete bien precise qui est
responsable du plantage. Dans ce cas il rajoute juste la ligne qu'il
faut dans le corps de la methode et c'est finit.
Dans ton cas, il risque d'abord de mettre un petit peu de temps a
comprendre que le setter est genere par un template. Ensuite il doit
se taper l'écriture de la méthode from scratch.
Faire en sorte que ton éditeur te génère des getters/setters qui vont
bien d'un simple raccourci c'est facile, autant ne pas s'en priver.
En fait, ça me rappelle un article que j'avais lu une fois sur un blog
d'un développeur C++. Il constatait que les gens abusaient trop
souvent des "figures de style" que leur proposaient les langages pour
faire du code qui au final était tricky mais pas naturel et a la
longue peu lisible.
Voici l'article d'ailleurs:
http://binstock.blogspot.com/2007/12/beautiful-code-vs-readable-code.html
> Dans le cas ou les
> getters/setters sont écrits explicitement dans le source-code il se
> rendra vite compte que dans ton setter tu ne vérifies jamais que x est
> non null ou qu'il verifie une propriete bien precise qui est
> responsable du plantage.
Si le getter/setter provient d'un mixin, tu sais qu'il est bete et mechant. Si
tu dois introduire des contrats (non null, etc...) tu implementes le getter
et/ou le setter a la main.
Je te precise egalement que si tes getters/setters sont ecrits a la main, tu
peux faire des erreures du type :
in x() { return y_; } // return y_ au lieux de return x_
Ces erreures sont vicieuses, facile a comettre quand tu penses a deux choses a
la fois, que tu codes, que tu es fatigue et que tu regardes un film de cul en
bas a droite de ton ecran; et pas forcement facile a reperer si tu as 20
getters qui sont tous sence etre "bete et mechant" => se ressemblent tous =>
chiant a lire => on les lits en diagonale => on ne les lits pas.
Ecrire un setter via des mixin, permet de faire des choses du style :
void DebugCondition(DebugCondition node)
{
static if (typeof (node) == DebugCondition)
AssertValidDebugCondition(node);
debugCondition_ = node;
}
de facons automatique et non intrusives dans tes getters/setters. Ca te permet
egalement de generer des informations statistiques a la volee si tu compiles
en version = XXX; pour faire de l'optimisation par la suite et tout et tout.
De facons non intrusive :-)
> Dans ce cas il rajoute juste la ligne qu'il
> faut dans le corps de la methode et c'est finit.
Si tu dois ajouter un test sur le setter, tu changes la mixin SetterAndGetter
a Getter et tu implementes le setter.
> Dans ton cas, il risque d'abord de mettre un petit peu de temps a
> comprendre que le setter est genere par un template. Ensuite il doit
> se taper l'écriture de la méthode from scratch.
J'espere qu'on aura un handbook pour boostraper les nouveaux developers.
J'aimerais bien que le projet soit "facilement comprehensible". Mais si du
code est repetitif, il doit etre factorise et/ou generer mais pas ecrit a la
main. Je pense au contraire qu'il vaut mieux maitriser un concepte que tu
develope plutot que lire de facons attentive les 200~300+ getters/setters
qu'il y aura dans l'AST et noyer les "vraix" getters parmis les getters "betes
et factorisable".
> Faire en sorte que ton éditeur te génère des getters/setters qui vont
> bien d'un simple raccourci c'est facile, autant ne pas s'en priver.
Imagines que tu as genere 150 setters avec vim, tu as envie de rajouter un
assert : assert(node !is null, "Chiche, t'es nulle :p"); dans tes 150 setters
juste apres ? (on suppose que ce sont 150 setters bete et mechant).
> En fait, ça me rappelle un article que j'avais lu une fois sur un blog
> d'un développeur C++. Il constatait que les gens abusaient trop
> souvent des "figures de style" que leur proposaient les langages pour
> faire du code qui au final était tricky mais pas naturel et a la
> longue peu lisible.
> Voici l'article d'ailleurs:
> http://binstock.blogspot.com/2007/12/beautiful-code-vs-readable-code.html
Ben oui mais bon pour enfoncer des clous il faut savoir se servir d'un
marteau. Apres il y a des limites mais je considere pas qu'un mixin qui genere
un getter/setter c'est de l'obfuscation. Surtout quand les imports t'aident a
savoir d'ou vient quoi, que tu peux t'appuyer sur de la doc et que le D, c'est
relativement facile a relire.
--
Alexandre Bique (bique.a...@gmail.com)
Epita 2009 - Yaka - GISTR
> > Donc on va vite considerer le fait qu'il faut des getters/setters. La
> > question suivante est quelle convention de nomage ?
> > Je suis favorable a la notation :
> > int salaire(); // getter
> > void salaire(int); // setter
>
> Ben c'est la syntaxe des propriétés si je ne m'abuse...
Oui mais on aurait put faire autrement, x_get et x_set ou x() et setX()
> Enfin presque => int salaire(int) // setter
Pourquoi pas retourner quelque chose, mais est-ce que ca fait vraiment sens ?
--
Alexandre Bique (bique.a...@gmail.com)
Epita 2009 - Yaka - GISTR
Par contre, ton exemple sur les 150 setters générés avec ton éditeur
préféré et de devoir les modifier pour rajouter un assert. Tu te
retrouves avec le même problème si tu as utilisé des mixins pour les
générer et que tu en as 150 autres que tu ne veux pas modifier !
> Par contre, ton exemple sur les 150 setters générés avec ton éditeur
> préféré et de devoir les modifier pour rajouter un assert. Tu te
> retrouves avec le même problème si tu as utilisé des mixins pour les
> générer et que tu en as 150 autres que tu ne veux pas modifier !
Pas forcement, tu peux peut-etre faire du static if :-)