Richard Delorme a écrit :Le 26/01/2010 19:35, Marc Espie a écrit :In article<4b5f22b7$0$17500$,
Richard Delorme wrote:La réalité peut être plus complexe. En pratique une classe peut-être
assez compliquée et n'avoir besoin que d'une partie de ses variables
initialisées selon la situation. Tout initialiser dans le constructeur
(ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
causer des problèmes de performances. L'idéal est de n'initialiser que
ce qui est nécessaire avant son utilisation.
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu
essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Entièrement d'accord avec toi.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas
sur la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
La valeur du coup, la variable value, est issue d'un long calcul. A
quoi bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception.
C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
Pour moi, l'état indéterminée d'une variable a du sens et je ne
comprends pas cette volonté de mettre une valeur déterminée à tout prix
pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéterminé.
C'est forcément le signe d'un défaut de conception quelque part.
En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.Les données du coup sont initialisées directement depuis son conteneur
(un tableau de coups), car il est plus simple de générer l'ensemble
des coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
la manière idiomatique qu'utilise tous les programmes d'un niveau
acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
Richard Delorme a écrit :
Le 26/01/2010 19:35, Marc Espie a écrit :
In article<4b5f22b7$0$17500$ba4acef3@news.orange.fr>,
Richard Delorme<abulmo@nospam.fr> wrote:
La réalité peut être plus complexe. En pratique une classe peut-être
assez compliquée et n'avoir besoin que d'une partie de ses variables
initialisées selon la situation. Tout initialiser dans le constructeur
(ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
causer des problèmes de performances. L'idéal est de n'initialiser que
ce qui est nécessaire avant son utilisation.
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu
essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Entièrement d'accord avec toi.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas
sur la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
La valeur du coup, la variable value, est issue d'un long calcul. A
quoi bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception.
C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
Pour moi, l'état indéterminée d'une variable a du sens et je ne
comprends pas cette volonté de mettre une valeur déterminée à tout prix
pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéterminé.
C'est forcément le signe d'un défaut de conception quelque part.
En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.
Les données du coup sont initialisées directement depuis son conteneur
(un tableau de coups), car il est plus simple de générer l'ensemble
des coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
la manière idiomatique qu'utilise tous les programmes d'un niveau
acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
Richard Delorme a écrit :Le 26/01/2010 19:35, Marc Espie a écrit :In article<4b5f22b7$0$17500$,
Richard Delorme wrote:La réalité peut être plus complexe. En pratique une classe peut-être
assez compliquée et n'avoir besoin que d'une partie de ses variables
initialisées selon la situation. Tout initialiser dans le constructeur
(ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
causer des problèmes de performances. L'idéal est de n'initialiser que
ce qui est nécessaire avant son utilisation.
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu
essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Entièrement d'accord avec toi.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas
sur la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
La valeur du coup, la variable value, est issue d'un long calcul. A
quoi bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception.
C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
Pour moi, l'état indéterminée d'une variable a du sens et je ne
comprends pas cette volonté de mettre une valeur déterminée à tout prix
pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéterminé.
C'est forcément le signe d'un défaut de conception quelque part.
En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.Les données du coup sont initialisées directement depuis son conteneur
(un tableau de coups), car il est plus simple de générer l'ensemble
des coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
la manière idiomatique qu'utilise tous les programmes d'un niveau
acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Piece promotion;
Piece promotion;
Piece promotion;
In article<4b5fded2$0$928$,
Richard Delorme wrote:Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
In article<4b5fded2$0$928$ba4acef3@news.orange.fr>,
Richard Delorme<abulmo@nospam.fr> wrote:
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
In article<4b5fded2$0$928$,
Richard Delorme wrote:Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
Le 27/01/2010 15:33, Stan a écrit :Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
J'utilise pas mal d'énumération (qui ont un typage plus fort qu'en C).
De la programmation objet, j'utilise l'encapsulation, et c'est à peu
prêt tout. Pas d'héritage non que je soit contre, mais je n'en ai pas
d'usage.
La gestion des erreurs par try/catch (en particulier sur tout ce qui est
entrée par l'utilisateur (ou depuis un fichier, une interface graphique,
etc.).
Les I/O et les strings du C++.
Le RAII par endroit.
Les conteneurs de la bibliothèque standard, j'en ai utilisé au début
(prototypage plus rapide), mais il ne doit plus rien rester,
effectivement pour des questions de performances.
Quelque template, mais ça reste rare.
Je n'utilise a peu prêt rien de la bibliothèque du langage C, sauf les
assertions (test des préconditions et des post-conditions) et ce qui est
inévitable (thread, gestion du temps, etc.), mais en encapsulant ça dans
des classes C++.
J'utilise new/delete, mais tout est alloué au début du programme et
détruit en fin de programme. Il ne doit y avoir que très peu d'autres
allocations (et en tout cas aucune dans les parties sensibles à la
performance).
Pour faire simple, j'utilise le C++ comme il y a 15 ans, à quelques
exceptions prêts.
Un programme d'échecs assez intéressant est "fruit (de Fabien Letouzey)
" qui utilise le C++ comme un "better C" et sa surchage de fonctions.
Pas de classes, pas d'I/O C++, etc.
Sur les forums d'échecs, la question du "meilleur langage" revient
souvent et les vertus/défauts du C++ y sont souvent débattus :
http://talkchess.com/forum/viewtopic.php?p11921#311921
http://talkchess.com/forum/viewtopic.php?p%7552#257552
Le 27/01/2010 15:33, Stan a écrit :
Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
J'utilise pas mal d'énumération (qui ont un typage plus fort qu'en C).
De la programmation objet, j'utilise l'encapsulation, et c'est à peu
prêt tout. Pas d'héritage non que je soit contre, mais je n'en ai pas
d'usage.
La gestion des erreurs par try/catch (en particulier sur tout ce qui est
entrée par l'utilisateur (ou depuis un fichier, une interface graphique,
etc.).
Les I/O et les strings du C++.
Le RAII par endroit.
Les conteneurs de la bibliothèque standard, j'en ai utilisé au début
(prototypage plus rapide), mais il ne doit plus rien rester,
effectivement pour des questions de performances.
Quelque template, mais ça reste rare.
Je n'utilise a peu prêt rien de la bibliothèque du langage C, sauf les
assertions (test des préconditions et des post-conditions) et ce qui est
inévitable (thread, gestion du temps, etc.), mais en encapsulant ça dans
des classes C++.
J'utilise new/delete, mais tout est alloué au début du programme et
détruit en fin de programme. Il ne doit y avoir que très peu d'autres
allocations (et en tout cas aucune dans les parties sensibles à la
performance).
Pour faire simple, j'utilise le C++ comme il y a 15 ans, à quelques
exceptions prêts.
Un programme d'échecs assez intéressant est "fruit (de Fabien Letouzey)
" qui utilise le C++ comme un "better C" et sa surchage de fonctions.
Pas de classes, pas d'I/O C++, etc.
Sur les forums d'échecs, la question du "meilleur langage" revient
souvent et les vertus/défauts du C++ y sont souvent débattus :
http://talkchess.com/forum/viewtopic.php?p11921#311921
http://talkchess.com/forum/viewtopic.php?p%7552#257552
Le 27/01/2010 15:33, Stan a écrit :Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).
J'utilise pas mal d'énumération (qui ont un typage plus fort qu'en C).
De la programmation objet, j'utilise l'encapsulation, et c'est à peu
prêt tout. Pas d'héritage non que je soit contre, mais je n'en ai pas
d'usage.
La gestion des erreurs par try/catch (en particulier sur tout ce qui est
entrée par l'utilisateur (ou depuis un fichier, une interface graphique,
etc.).
Les I/O et les strings du C++.
Le RAII par endroit.
Les conteneurs de la bibliothèque standard, j'en ai utilisé au début
(prototypage plus rapide), mais il ne doit plus rien rester,
effectivement pour des questions de performances.
Quelque template, mais ça reste rare.
Je n'utilise a peu prêt rien de la bibliothèque du langage C, sauf les
assertions (test des préconditions et des post-conditions) et ce qui est
inévitable (thread, gestion du temps, etc.), mais en encapsulant ça dans
des classes C++.
J'utilise new/delete, mais tout est alloué au début du programme et
détruit en fin de programme. Il ne doit y avoir que très peu d'autres
allocations (et en tout cas aucune dans les parties sensibles à la
performance).
Pour faire simple, j'utilise le C++ comme il y a 15 ans, à quelques
exceptions prêts.
Un programme d'échecs assez intéressant est "fruit (de Fabien Letouzey)
" qui utilise le C++ comme un "better C" et sa surchage de fonctions.
Pas de classes, pas d'I/O C++, etc.
Sur les forums d'échecs, la question du "meilleur langage" revient
souvent et les vertus/défauts du C++ y sont souvent débattus :
http://talkchess.com/forum/viewtopic.php?p11921#311921
http://talkchess.com/forum/viewtopic.php?p%7552#257552
In article <4b5fded2$0$928$,
Richard Delorme wrote:Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
In article <4b5fded2$0$928$ba4acef3@news.orange.fr>,
Richard Delorme <abulmo@nospam.fr> wrote:
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
In article <4b5fded2$0$928$,
Richard Delorme wrote:Le 26/01/2010 19:35, Marc Espie a écrit :Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.
Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :
class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;
// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?
Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.
Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?
Ou sont les roques dans tout ca ?
Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.
J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.
Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
En approche objet, je n'utilise jamais des enums. Je passe toujours par
l'héritage.
Un enum, c'est une classe abstraite et il y a autant de sous-classes que
de valeurs dans l'enum.
En approche objet, je n'utilise jamais des enums. Je passe toujours par
l'héritage.
Un enum, c'est une classe abstraite et il y a autant de sous-classes que
de valeurs dans l'enum.
En approche objet, je n'utilise jamais des enums. Je passe toujours par
l'héritage.
Un enum, c'est une classe abstraite et il y a autant de sous-classes que
de valeurs dans l'enum.
Richard Delorme a écrit :
> Le 26/01/2010 19:35, Marc Espie a écrit :
>> In article<4b5f22b7$0$17500$,
>> Richard Delorme wrote:
>>> La réalité peut être plus complexe. En pratique une classe peut -être
>>> assez compliquée et n'avoir besoin que d'une partie de ses variable s
>>> initialisées selon la situation. Tout initialiser dans le construct eur
>>> (ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
>>> causer des problèmes de performances. L'idéal est de n'initialise r que
>>> ce qui est nécessaire avant son utilisation.
>> Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
>> pouvoir tomber sur ce genre de choses, c'est generalement que tu
>> essaies de
>> lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
>> decoupee en morceaux plus petits, pour lesquels ce genre de souci ne s e
>> poserait plus.
Entièrement d'accord avec toi.
> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éche c.
> Une implémentation simplifiée sous forme de classe pourrait être :
> class Move {
> // fonctions membres privées
> public:
> struct {
> Coordinate x;
> Piece piece;
> } from, to;
> Piece promotion;
> int value;
> // fonctions membres publiques.
> }
> Pourquoi initialiser la variable promotion si la pièce de départ n' est
> pas un pion, où, même si c'est un pion, la case d'arrivée n'est p as sur
> la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
> La valeur du coup, la variable value, est issue d'un long calcul. A quo i
> bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception. C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
> Pour moi, l'état indéterminée d'une variable a du sens et je ne
> comprends pas cette volonté de mettre une valeur déterminée à t out prix
> pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéter miné.
C'est forcément le signe d'un défaut de conception quelque part.
> En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.
> Les données du coup sont initialisées directement depuis son conten eur
> (un tableau de coups), car il est plus simple de générer l'ensemble des
> coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
> Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
> la manière idiomatique qu'utilise tous les programmes d'un niveau
> acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
[couic valgrind : mais je suis d'accord avec Marc]
Richard Delorme a écrit :
> Le 26/01/2010 19:35, Marc Espie a écrit :
>> In article<4b5f22b7$0$17500$ba4ac...@news.orange.fr>,
>> Richard Delorme<abu...@nospam.fr> wrote:
>>> La réalité peut être plus complexe. En pratique une classe peut -être
>>> assez compliquée et n'avoir besoin que d'une partie de ses variable s
>>> initialisées selon la situation. Tout initialiser dans le construct eur
>>> (ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
>>> causer des problèmes de performances. L'idéal est de n'initialise r que
>>> ce qui est nécessaire avant son utilisation.
>> Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
>> pouvoir tomber sur ce genre de choses, c'est generalement que tu
>> essaies de
>> lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
>> decoupee en morceaux plus petits, pour lesquels ce genre de souci ne s e
>> poserait plus.
Entièrement d'accord avec toi.
> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éche c.
> Une implémentation simplifiée sous forme de classe pourrait être :
> class Move {
> // fonctions membres privées
> public:
> struct {
> Coordinate x;
> Piece piece;
> } from, to;
> Piece promotion;
> int value;
> // fonctions membres publiques.
> }
> Pourquoi initialiser la variable promotion si la pièce de départ n' est
> pas un pion, où, même si c'est un pion, la case d'arrivée n'est p as sur
> la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
> La valeur du coup, la variable value, est issue d'un long calcul. A quo i
> bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception. C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
> Pour moi, l'état indéterminée d'une variable a du sens et je ne
> comprends pas cette volonté de mettre une valeur déterminée à t out prix
> pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéter miné.
C'est forcément le signe d'un défaut de conception quelque part.
> En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.
> Les données du coup sont initialisées directement depuis son conten eur
> (un tableau de coups), car il est plus simple de générer l'ensemble des
> coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
> Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
> la manière idiomatique qu'utilise tous les programmes d'un niveau
> acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
[couic valgrind : mais je suis d'accord avec Marc]
Richard Delorme a écrit :
> Le 26/01/2010 19:35, Marc Espie a écrit :
>> In article<4b5f22b7$0$17500$,
>> Richard Delorme wrote:
>>> La réalité peut être plus complexe. En pratique une classe peut -être
>>> assez compliquée et n'avoir besoin que d'une partie de ses variable s
>>> initialisées selon la situation. Tout initialiser dans le construct eur
>>> (ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
>>> causer des problèmes de performances. L'idéal est de n'initialise r que
>>> ce qui est nécessaire avant son utilisation.
>> Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
>> pouvoir tomber sur ce genre de choses, c'est generalement que tu
>> essaies de
>> lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
>> decoupee en morceaux plus petits, pour lesquels ce genre de souci ne s e
>> poserait plus.
Entièrement d'accord avec toi.
> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éche c.
> Une implémentation simplifiée sous forme de classe pourrait être :
> class Move {
> // fonctions membres privées
> public:
> struct {
> Coordinate x;
> Piece piece;
> } from, to;
> Piece promotion;
> int value;
> // fonctions membres publiques.
> }
> Pourquoi initialiser la variable promotion si la pièce de départ n' est
> pas un pion, où, même si c'est un pion, la case d'arrivée n'est p as sur
> la dernière rangée ?
Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?
> La valeur du coup, la variable value, est issue d'un long calcul. A quo i
> bon y mettre une valeur bidon ?
Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception. C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.
> Pour moi, l'état indéterminée d'une variable a du sens et je ne
> comprends pas cette volonté de mettre une valeur déterminée à t out prix
> pour tout.
Non, il n'y a aucun sens à avoir des variables avec un état indéter miné.
C'est forcément le signe d'un défaut de conception quelque part.
> En pratique, cette classe ne contient ni constructeur ni destructeur.
C'est déjà mauvais signe.
> Les données du coup sont initialisées directement depuis son conten eur
> (un tableau de coups), car il est plus simple de générer l'ensemble des
> coups (ou tout du moins d'une famille de coups), qu'un coup isolé.
D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.
> Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
> la manière idiomatique qu'utilise tous les programmes d'un niveau
> acceptable écrit en C++.
Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.
[couic valgrind : mais je suis d'accord avec Marc]
Le 27/01/2010 09:17, Wykaaa a écrit :
> Richard Delorme a écrit :
>> Le 26/01/2010 19:35, Marc Espie a écrit :
>>> In article<4b5f22b7$0$17500$,
>> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éch ec.
>> Une implémentation simplifiée sous forme de classe pourrait être :
>> class Move {
>> // fonctions membres privées
>> public:
>> struct {
>> Coordinate x;
>> Piece piece;
>> } from, to;
>> Piece promotion;
>> int value;
>> // fonctions membres publiques.
>> }
>> Pourquoi initialiser la variable promotion si la pièce de
>> départ n'est pas un pion, où, même si c'est un pion, la
>> case d'arrivée n'est pas sur la dernière rangée ?
> Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
> promotion ?
Parce que, conceptuellement, la promotion est un attribut du coup.
>> La valeur du coup, la variable value, est issue d'un long
>> calcul. A quoi bon y mettre une valeur bidon ?
> Si, à l'initialisation d'une instance de classe, il y a des
> attributs qu'on ne sait pas initialiser dans le
> constructeur, c'est qu'il y a un défaut de conception.
Pour "value" je fais comment? Pour moi la mauvaise réflexion
est de ce demander si je vais pouvoir initialiser (autrement
qu'avec une valeur bidon) une variable pour décider de la
rendre membre ou non. C'est ce focaliser sur un dogme qui ne
fait pas partie du langage mais juste une opinion sur ce
qu'est une hypothétique bonne conduite. Moi je préfère être
pragmatique. Mes coups, aux échecs, je les note. Cette note
est pour moi, indépendamment de tout langage de programmation
un attribut du coup. donc elle doit faire partie de la classe
Move.
> C'est le cas de ta classe Move car "promotion" ne
> doit pas se trouver là.
Ah et ou ça alors ?
En notation algébrique standard (SAN) on écrit p.ex., hxg1=Q.
Si je doit lire un tel coup, il faut bien que je stocke le =Q
quelque part ?
Maintenant si le coup est Qd4, la promotion
n'a pas de sens. Ma fonction pour lire de tel coup se présente
comme ça :
void Move::from_SAN(std::istream &is, const Board &board);
et à l'usage c'est juste un move.from_SAN(is, board); qu'il y
ait un coup avec ou sans promotion, m'importe peu. Si je met
la promotion ailleurs, je ne vois pas comment lire ce coup de
manière aussi simple.
>> Pour moi, l'état indéterminée d'une variable a du sens et
>> je ne comprends pas cette volonté de mettre une valeur
>> déterminée à tout prix pour tout.
> Non, il n'y a aucun sens à avoir des variables avec un état indét erminé.
Si, ça représente un état de connaissance partiel des membres
de la classe.
> Ton exemple est totalement anti-pattern, effectivement.
Je n'en suis pas sûr. Une conception inefficace en terme de
performance est un anti-pattern.
Le 27/01/2010 09:17, Wykaaa a écrit :
> Richard Delorme a écrit :
>> Le 26/01/2010 19:35, Marc Espie a écrit :
>>> In article<4b5f22b7$0$17500$ba4ac...@news.orange.fr>,
>> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éch ec.
>> Une implémentation simplifiée sous forme de classe pourrait être :
>> class Move {
>> // fonctions membres privées
>> public:
>> struct {
>> Coordinate x;
>> Piece piece;
>> } from, to;
>> Piece promotion;
>> int value;
>> // fonctions membres publiques.
>> }
>> Pourquoi initialiser la variable promotion si la pièce de
>> départ n'est pas un pion, où, même si c'est un pion, la
>> case d'arrivée n'est pas sur la dernière rangée ?
> Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
> promotion ?
Parce que, conceptuellement, la promotion est un attribut du coup.
>> La valeur du coup, la variable value, est issue d'un long
>> calcul. A quoi bon y mettre une valeur bidon ?
> Si, à l'initialisation d'une instance de classe, il y a des
> attributs qu'on ne sait pas initialiser dans le
> constructeur, c'est qu'il y a un défaut de conception.
Pour "value" je fais comment? Pour moi la mauvaise réflexion
est de ce demander si je vais pouvoir initialiser (autrement
qu'avec une valeur bidon) une variable pour décider de la
rendre membre ou non. C'est ce focaliser sur un dogme qui ne
fait pas partie du langage mais juste une opinion sur ce
qu'est une hypothétique bonne conduite. Moi je préfère être
pragmatique. Mes coups, aux échecs, je les note. Cette note
est pour moi, indépendamment de tout langage de programmation
un attribut du coup. donc elle doit faire partie de la classe
Move.
> C'est le cas de ta classe Move car "promotion" ne
> doit pas se trouver là.
Ah et ou ça alors ?
En notation algébrique standard (SAN) on écrit p.ex., hxg1=Q.
Si je doit lire un tel coup, il faut bien que je stocke le =Q
quelque part ?
Maintenant si le coup est Qd4, la promotion
n'a pas de sens. Ma fonction pour lire de tel coup se présente
comme ça :
void Move::from_SAN(std::istream &is, const Board &board);
et à l'usage c'est juste un move.from_SAN(is, board); qu'il y
ait un coup avec ou sans promotion, m'importe peu. Si je met
la promotion ailleurs, je ne vois pas comment lire ce coup de
manière aussi simple.
>> Pour moi, l'état indéterminée d'une variable a du sens et
>> je ne comprends pas cette volonté de mettre une valeur
>> déterminée à tout prix pour tout.
> Non, il n'y a aucun sens à avoir des variables avec un état indét erminé.
Si, ça représente un état de connaissance partiel des membres
de la classe.
> Ton exemple est totalement anti-pattern, effectivement.
Je n'en suis pas sûr. Une conception inefficace en terme de
performance est un anti-pattern.
Le 27/01/2010 09:17, Wykaaa a écrit :
> Richard Delorme a écrit :
>> Le 26/01/2010 19:35, Marc Espie a écrit :
>>> In article<4b5f22b7$0$17500$,
>> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éch ec.
>> Une implémentation simplifiée sous forme de classe pourrait être :
>> class Move {
>> // fonctions membres privées
>> public:
>> struct {
>> Coordinate x;
>> Piece piece;
>> } from, to;
>> Piece promotion;
>> int value;
>> // fonctions membres publiques.
>> }
>> Pourquoi initialiser la variable promotion si la pièce de
>> départ n'est pas un pion, où, même si c'est un pion, la
>> case d'arrivée n'est pas sur la dernière rangée ?
> Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
> promotion ?
Parce que, conceptuellement, la promotion est un attribut du coup.
>> La valeur du coup, la variable value, est issue d'un long
>> calcul. A quoi bon y mettre une valeur bidon ?
> Si, à l'initialisation d'une instance de classe, il y a des
> attributs qu'on ne sait pas initialiser dans le
> constructeur, c'est qu'il y a un défaut de conception.
Pour "value" je fais comment? Pour moi la mauvaise réflexion
est de ce demander si je vais pouvoir initialiser (autrement
qu'avec une valeur bidon) une variable pour décider de la
rendre membre ou non. C'est ce focaliser sur un dogme qui ne
fait pas partie du langage mais juste une opinion sur ce
qu'est une hypothétique bonne conduite. Moi je préfère être
pragmatique. Mes coups, aux échecs, je les note. Cette note
est pour moi, indépendamment de tout langage de programmation
un attribut du coup. donc elle doit faire partie de la classe
Move.
> C'est le cas de ta classe Move car "promotion" ne
> doit pas se trouver là.
Ah et ou ça alors ?
En notation algébrique standard (SAN) on écrit p.ex., hxg1=Q.
Si je doit lire un tel coup, il faut bien que je stocke le =Q
quelque part ?
Maintenant si le coup est Qd4, la promotion
n'a pas de sens. Ma fonction pour lire de tel coup se présente
comme ça :
void Move::from_SAN(std::istream &is, const Board &board);
et à l'usage c'est juste un move.from_SAN(is, board); qu'il y
ait un coup avec ou sans promotion, m'importe peu. Si je met
la promotion ailleurs, je ne vois pas comment lire ce coup de
manière aussi simple.
>> Pour moi, l'état indéterminée d'une variable a du sens et
>> je ne comprends pas cette volonté de mettre une valeur
>> déterminée à tout prix pour tout.
> Non, il n'y a aucun sens à avoir des variables avec un état indét erminé.
Si, ça représente un état de connaissance partiel des membres
de la classe.
> Ton exemple est totalement anti-pattern, effectivement.
Je n'en suis pas sûr. Une conception inefficace en terme de
performance est un anti-pattern.