Getters Setters et ABI

0 views
Skip to first unread message

Alexandre Bique

unread,
Apr 28, 2008, 6:48:33 PM4/28/08
to dcom...@googlegroups.com
Salut,

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

Matías Larre Borges

unread,
Apr 28, 2008, 7:16:28 PM4/28/08
to dcom...@googlegroups.com
2008/4/29 Alexandre Bique <bique.a...@gmail.com>:
>
> Salut,
Lut!
>
> [...]

>
> 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 ?

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

Alexandre Bique

unread,
Apr 29, 2008, 5:06:22 AM4/29/08
to dcom...@googlegroups.com
2008/4/29 Matías Larre Borges <lan...@gmail.com>:
> 2008/4/29 Alexandre Bique <bique.a...@gmail.com>:

> > 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 ?
>
> 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 est daccord la dessus l'interet du D c'est que si tu as une classe
class X
{
public: void branle(int x)
{
// my func;
}
}

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

Alexandre Bique

unread,
Apr 29, 2008, 12:09:56 PM4/29/08
to dcompiler
Un autre probleme avec les properties du langage D (merci a Paul
Baudron) :

class X
{
public:
void branle(int x) { branle_ = x; }
int branle() { return branle_; }
private:
int branle_;
}

int main()
{
X x = new X();

x.branle = 42; // Ok, appelle X.branle(42);
x.branle += 4; // Error: 'x.branle' is not a scalar, it is a
void(int x) ...
return 0;
}

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

Daccord/Pas daccord/Suggestion ?

--
Alexandre Bique (bique.alexan...@gmail.com)

Arkanosis

unread,
Apr 29, 2008, 12:15:47 PM4/29/08
to dcom...@googlegroups.com
Le 29 avril 2008 18:09, Alexandre Bique <bique.a...@gmail.com> a écrit :
> Un autre probleme avec les properties du langage D (merci a Paul
> Baudron) :
> [...]
C'est pas intrinsèque au langage, c'est juste le compilateur qui n'est pas fini.

> 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

Ballas Nicolas

unread,
Apr 29, 2008, 12:23:38 PM4/29/08
to dcom...@googlegroups.com
C'est peu etre pas très D comme solution, mais doit y'avoir
moyen de renvoyer une reference, soit constante soit pas constante.
Ainsi T'y accede de maniere (presque transparente).

--
Nicolas Ballas

Arkanosis

unread,
Apr 29, 2008, 12:34:42 PM4/29/08
to dcom...@googlegroups.com
2008/4/29 Ballas Nicolas <ball...@gmail.com>:

> C'est peu etre pas très D comme solution, mais doit y'avoir
> moyen de renvoyer une reference, soit constante soit pas constante.
> Ainsi T'y accede de maniere (presque transparente).
En fait les références sont gérées automatiquement par le langage :
référence pour les class, copie pour les scalaires et les structs.
Pour la constitude, malheureusement, il n'y en a pas en D1.0.

--
Arkanosis

Matías Larre Borges

unread,
Apr 29, 2008, 1:33:27 PM4/29/08
to dcom...@googlegroups.com
2008/4/29 Alexandre Bique <bique.a...@gmail.com>:

> On est daccord la dessus l'interet du D c'est que si tu as une classe
> class X
> {
> public: void branle(int x)
> {
> // my func;
> }
> }
>
> tu peux ecrire
> X x = new X();
> int a = 42;
> X.branle = 42;
>
> L'avais-tu bien saisis ?
>
Oui, j'avais bien compris. Et je trouve que ce comportement est
justement la pour inciter les développeurs a utiliser des
getters/setters meme dans les cas ou il s'agit juste d'accéder
bêtement a une variable.

> [...]


> 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

Alexandre Bique

unread,
Apr 29, 2008, 7:03:07 PM4/29/08
to dcom...@googlegroups.com
On Tuesday 29 April 2008 19:33:27 Matías Larre Borges wrote:
> 2008/4/29 Alexandre Bique <bique.a...@gmail.com>:

> > [...]
> > 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.
Ce quelqu'un debogue un compilateur donc il y a un certains nombre de choses a
assimiler avant de commencer.

> 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

Alexandre Bique

unread,
Apr 29, 2008, 7:12:11 PM4/29/08
to dcom...@googlegroups.com
On Tuesday 29 April 2008 18:15:47 Arkanosis wrote:
> Le 29 avril 2008 18:09, Alexandre Bique <bique.a...@gmail.com> a écrit
:
> > Un autre probleme avec les properties du langage D (merci a Paul
> > Baudron) :
> > [...]
>
> C'est pas intrinsèque au langage, c'est juste le compilateur qui n'est pas
> fini.
Ah bon ? Il faudra que je regarde la grammaire en details, mais ca m'etonne.

> > 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

Matías Larre Borges

unread,
Apr 29, 2008, 7:15:03 PM4/29/08
to dcom...@googlegroups.com
2008/4/30 Alexandre Bique <bique.a...@gmail.com>:
> [...]
Après une lecture attentive de ces arguments, je rejoins ton point de
vue. Il faudra faire attention à ne pas abuser des mixins et se
débrouiller pour qu'ils soient explicites.

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 !

Alexandre Bique

unread,
Apr 29, 2008, 7:31:01 PM4/29/08
to dcom...@googlegroups.com
On Wednesday 30 April 2008 01:15:03 Matías Larre Borges wrote:
> Après une lecture attentive de ces arguments, je rejoins ton point de
> vue. Il faudra faire attention à ne pas abuser des mixins et se
> débrouiller pour qu'ils soient explicites.
Oui nous sommes daccord sur ce point.

> 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 :-)

Reply all
Reply to author
Forward
0 new messages