J'ai lu avec grand intérêt l'article "Concepts for C++0x" mentionné dans
un thread récent.
Habituellement, je ne m'intéresse pas aux évolutions du langage car
elles ne me concernent qu'à un relativement long terme, mais là, j'ai
l'impression qu'un mouvement de fond relatif aux paradygmes du C++ prend
une certaine ampleur.
Et ce mouvement m'amène à quelques interrogations.
La plupart des développeurs que je cotoie programment en C++ dans un
style orienté objet très proche de ce que l'on trouve en Java.
Je prends un exemple classique de Bridge+Factory pour illustrer mon propos.
On a typiquement une hiérarchie d'implémentations :
| class DocumentDisplay {
| virtual ~DocumentDisplay();
| virtual void drawText( int x, int y, std::string const &text ) = 0;
| virtual void drawLine( int x1, int y1, int x2, int y2 ) = 0;
| };
|
| class GraphicDocumentDisplay : public DocumentDisplay {
| virtual void drawText( int x, int y, std::string const &text );
| virtual void drawLine( int x1, int y1, int x2, int y2 );
| };
|
| class TextDocumentDisplay : public DocumentDisplay {
| ...
une hiérarchie d'abstractions qui utilisent les implémentations :
|
| class Document {
| public:
| Document( DocumentDisplay *display ) : display_(display) {}
| virtual ~Document();
|
| void drawFrame( int x, int y, int w, int h, std::string const &title ) {
| display_->drawLine( x, y, x+w, y );
| display_->drawLine( x, y+h, x+w, y+h );
| display_->drawText( x, y, title );
| }
| private:
| DocumentDisplay *display_;
| };
|
| class Memo : public Document {
| public:
| Memo( DocumentDisplay *display ) : Document(display) {}
| void drawSummary() { drawFrame( 0, 0, 150, 100, "Summary" ); }
| };
|
| class Invoice : public Document {
| ...
une hiérarchie de fabriques pour instancier tout ça :
| class DocumentFactory {
| public:
| virtual ~DocumentFactory() {}
| virtual Memo *createMemo() = 0;
| virtual Invoice *createInvoice() = 0;
| };
|
| class GraphicDocumentFactory : public DocumentFactory {
| public:
| virtual Memo *createMemo() { return new Memo( new
GraphicDocumentDisplay ); }
| virtual Invoice *createInvoice() { return new Invoice( new
GraphicDocumentDisplay ); }
| };
et je rajoute un programme principal pour utiliser le tout :
| class Application {
| public:
| Application( DocumentFactory *factory ) : factory_(factory) {}
|
| void run() {
| Memo *memo = factory_->createMemo();
| memo->drawSummary();
| }
| private:
| DocumentFactory *factory_;
| };
|
| int main() {
| Application app( new GraphicDocumentFactory );
| app.run();
| }
En pratique, ça a une tête un peu différente (avec le RAII par exemple),
mais l'idée des hiérarchie de classes est là.
Depuis quelques temps se répand la programmation générique qui permet de
faire la même chose avec (en général) moins de lignes de code.
Les implémentations deviennent des "policy" et n'ont plus besoin de
classe de base
| class GraphicDocumentDisplay {
| virtual void drawText( int x, int y, std::string const &text );
| virtual void drawLine( int x1, int y1, int x2, int y2 );
| };
Les abstractions sont paramétrées par la policy.
On garde un héritage pour partager l'implémentation :
| template <class DOCDISP>
| class Document {
| public:
| virtual ~Document() {}
|
| void drawFrame( int x, int y, int w, int h, std::string const &title ) {
| display_.drawLine( x, y, x+w, y );
| display_.drawLine( x, y+h, x+w, y+h );
| display_.drawText( x, y, title );
| }
| private:
| DOCDISP display_;
| };
|
| template <class DOCDISP>
| class Memo : public Document<DOCDISP> {
| public:
| void drawSummary() { drawFrame( 0, 0, 150, 100, "Summary" ); }
| };
Dans un cas aussi simple, on oublie la factory et on paramètre
directement l'application :
| template <class DOCDISP>
| class Application {
| public:
| void run() {
| Memo<DOCDISP> memo;
| memo.drawSummary();
| }
| };
|
| int main() {
| Application<GraphicDocumentDisplay> app;
| app.run();
| }
Une telle approche est actuellement plutôt prisée par des personnes qui
connaissent bien le langage et est donc globalement plutôt minoritaire.
Parmi les raisons de cette situation je vois :
- la forte présence de langages comme Java ou C# qui ne proposent pas
cette approche (les versions "Generic" restent anecdotiques) et donc le
grand nombre de personnes qui font du C++ comme ils font du Java
- le faible support des templates par certains compilateurs jusqu'à une
période récente (cf les interrogations récurrentes relatives au support
des templates dans VC6)
- un support méthodologique peu adapté (UML se prête beaucoup plus à
décrire des héritages que de paramétrages)
- une complexité de mise au point d'une approche à base de templates
(typage structurel, définitions statiques, ...)
Sur ce, je découvre les "concepts" (dont je ne pense pas avoir saisi le
dixième des utilisations et implications) qui me laissent supposer que,
dans un avenir plus ou moins proche, on pourrait écrire les choses de
manière plus explicites.
Les policy pourraient être nommées et contrôlées avant usage. Si j'ai
bien compris les notions et syntaxes proposées dans l'article, cela
donnerait quelque chose comme :
| template <DOCDISP>
| concept DisplaysDocuments {
| void DOCDISP::drawText( int x, int y, std::string const &text );
| void DOCDISP::drawLine( int x1, int y1, int x2, int y2 );
| };
|
| class GraphicDocumentDisplay {
| public:
| void drawText( int x, int y, std::string const &text );
| void drawLine( int x1, int y1, int x2, int y2 );
| };
|
| model DisplaysDocuments<GraphicDocumentDisplay>;
Et j'ai même l'impression que des implémentations par défaut définies au
niveau des concepts pourraient rendre obsolète une grand pan de
l'utilisation de l'héritage.
En écrivant par exemple ce qui suit, j'ai l'impression d'avoir
entièrement réécrit l'exemple vu précédemment sans utiliser aucun
héritage C++ mais avec l'impression d'avoir quand même fait de l'"objet"
(s'il est encore possible de définir ce terme...) mais "autrement".
| template <DOC>
| concept IsDocument {
| typename doc_display;
| require DisplaysDocuments<doc_display>;
|
| doc_display &DOC::display();
|
| void DOC::drawFrame( int x, int y, int w, int h, std::string const
&title ) {
| display().drawLine( x, y, x+w, y );
| display().drawLine( x, y+h, x+w, y+h );
| display().drawText( x, y, title );
| }
| };
|
| template <class DOCDISP>
| class Memo {
| public:
| typedef DOCDISP doc_display;
| doc_display &display() { return display_; }
|
| void drawSummary() { drawFrame( 0, 0, 150, 100, "Summary" ); }
| private:
| DOCDISP display_;
| };
|
| template <class DOCDISP>
| model IsDocument< Memo<DOCDISP> >;
Pour ceux qui auront eu le courage de lire jusqu'ici, j'aimerais savoir
s'ils pensent :
- que je n'ai rien compris aux "concepts" ?
- que ces notions vont avoir un impact technique majeur sur l'écriture
de code en C++ ?
- que ces notions vont avoir un impact sociologique majeur sur le
développement en C++ ?
Je suis plus particulièrement intéressé par l'aspect sociologique des
choses.
J'ai l'impression d'être face à une évolution du même ordre de grandeur
que le passage du C au C++.
Pour tout dire, j'ai même l'impression que le terme C++ n'est conservé
que pour des raisons marketing (la "marque" est déja connue, appréciée,
possède une base de consommateurs, ...)
Il est toujours possible d'écrire du C avec un compilateur C++ mais, sur
une période d'environ 10 ans (en gros les années 90) on est passé d'une
approche majoritaire en termes de structures/procédures a une approche
majoritaire classes/héritages/associations.
Cela a impliqué un changement de principes de modélisation, un
changement de techniques d'écriture de code mais surtout un changement
de mentalité.
Et quand je regarde les efforts qu'il a fallu déployer pour que
l'ensemble des intervenants en arrive à penser les développements plus
ou moins de la même manière, j'ai un peu l'impression, en voyant ces
nouvelles notions qui se profilent à l'horizon, que nous ne sommes pas
au bout de nos peines...
"Ivan Vecerina" a écrit dans le message news: cu1rmc$13o$
Le C++ a intégré la programmation objet au C, mais sous une forme "light" et peu couteuse en performance. Fonctions virtuelles pour le polymorphisme, et un rudiment d'embryon d'introspection avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk.
Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas mal de temps après les débuts. Et je me souviens de certains arguments : pourquoi voulez-vous connaître le type d'un objet à l'exécution, puique justement les fonctions virtuelles vous permettent de ne pas vous en soucier...
D'ailleurs "typeid()" n'est quasiment pas utilisé.
Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur ce genre de code : | A *a = monObjet(); | if( dynamic_cast<B*>(a) != NULL ) { | faireCeci(); | } else if( dynamic_cast<C*>(a) != NULL ) { | faireCela(); | } else if( dynamic_cast<D*>(a) != NULL ) { | faireCeciEtCela(); | } avec, bien sûr, B, C, et D qui héritent de A.
Alain Naigeon wrote:
"Ivan Vecerina" <INVALID_use_webform_instead@vecerina.com> a écrit dans le
message news: cu1rmc$13o$1@news.hispeed.ch...
Le C++ a intégré la programmation objet au C, mais sous une
forme "light" et peu couteuse en performance. Fonctions virtuelles
pour le polymorphisme, et un rudiment d'embryon d'introspection
avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk.
Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas mal
de temps après les débuts. Et je me souviens de certains arguments :
pourquoi voulez-vous connaître le type d'un objet à l'exécution,
puique justement les fonctions virtuelles vous permettent de ne pas vous
en soucier...
D'ailleurs "typeid()" n'est quasiment pas utilisé.
Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur
ce genre de code :
| A *a = monObjet();
| if( dynamic_cast<B*>(a) != NULL ) {
| faireCeci();
| } else if( dynamic_cast<C*>(a) != NULL ) {
| faireCela();
| } else if( dynamic_cast<D*>(a) != NULL ) {
| faireCeciEtCela();
| }
avec, bien sûr, B, C, et D qui héritent de A.
"Ivan Vecerina" a écrit dans le message news: cu1rmc$13o$
Le C++ a intégré la programmation objet au C, mais sous une forme "light" et peu couteuse en performance. Fonctions virtuelles pour le polymorphisme, et un rudiment d'embryon d'introspection avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk.
Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas mal de temps après les débuts. Et je me souviens de certains arguments : pourquoi voulez-vous connaître le type d'un objet à l'exécution, puique justement les fonctions virtuelles vous permettent de ne pas vous en soucier...
D'ailleurs "typeid()" n'est quasiment pas utilisé.
Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur ce genre de code : | A *a = monObjet(); | if( dynamic_cast<B*>(a) != NULL ) { | faireCeci(); | } else if( dynamic_cast<C*>(a) != NULL ) { | faireCela(); | } else if( dynamic_cast<D*>(a) != NULL ) { | faireCeciEtCela(); | } avec, bien sûr, B, C, et D qui héritent de A.
Gabriel Dos Reis
Olivier Azeau writes:
| Alain Naigeon wrote: | > "Ivan Vecerina" a écrit dans le | > message news: cu1rmc$13o$ | > | >>Le C++ a intégré la programmation objet au C, mais sous une | >>forme "light" et peu couteuse en performance. Fonctions virtuelles | >>pour le polymorphisme, et un rudiment d'embryon d'introspection | >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk. | > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas | > mal | > de temps après les débuts. Et je me souviens de certains arguments : | > pourquoi voulez-vous connaître le type d'un objet à l'exécution, | > puique justement les fonctions virtuelles vous permettent de ne pas vous | > en soucier... | | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-) Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
| Alain Naigeon wrote:
| > "Ivan Vecerina" <INVALID_use_webform_instead@vecerina.com> a écrit dans le
| > message news: cu1rmc$13o$1@news.hispeed.ch...
| >
| >>Le C++ a intégré la programmation objet au C, mais sous une
| >>forme "light" et peu couteuse en performance. Fonctions virtuelles
| >>pour le polymorphisme, et un rudiment d'embryon d'introspection
| >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk.
| > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas
| > mal
| > de temps après les débuts. Et je me souviens de certains arguments :
| > pourquoi voulez-vous connaître le type d'un objet à l'exécution,
| > puique justement les fonctions virtuelles vous permettent de ne pas vous
| > en soucier...
|
| D'ailleurs "typeid()" n'est quasiment pas utilisé.
|
| Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur
| ce genre de code :
| | A *a = monObjet();
| | if( dynamic_cast<B*>(a) != NULL ) {
| | faireCeci();
| | } else if( dynamic_cast<C*>(a) != NULL ) {
| | faireCela();
| | } else if( dynamic_cast<D*>(a) != NULL ) {
| | faireCeciEtCela();
| | }
| avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même
s'il en montre l'utilité dans certains cas (voir son bouquin). Mais
cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Par exemple, j'aurais tendance à privilégier une approche basée
sur « Visitor Design Pattern » qui sera souvent plus propre et
efficace qu'une série de if-else + dynamic_cast.
(Visitor Design Pattern est aux types ce que switch() est aux
expressions entière constantes).
| Alain Naigeon wrote: | > "Ivan Vecerina" a écrit dans le | > message news: cu1rmc$13o$ | > | >>Le C++ a intégré la programmation objet au C, mais sous une | >>forme "light" et peu couteuse en performance. Fonctions virtuelles | >>pour le polymorphisme, et un rudiment d'embryon d'introspection | >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk. | > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas | > mal | > de temps après les débuts. Et je me souviens de certains arguments : | > pourquoi voulez-vous connaître le type d'un objet à l'exécution, | > puique justement les fonctions virtuelles vous permettent de ne pas vous | > en soucier... | | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-) Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
-- Gaby
Ivan Vecerina
"Olivier Azeau" wrote in message news:jT2Nd.20674$
Ivan Vecerina wrote:
"Olivier Azeau" wrote in message news:ITTMd.20578$
Qu'est-ce qui définit "souvent" ? (qui finalement n'est qu'un synonyme de "la plupart")
Souvent ici est un très doux euphémisme. Voir ma réponse à Alain Naigeon pour voir ce que signifie le "tout-objet et tout-dynamique" dans un language comme SmallTalk. Peux-tu me citer quelques applications commerciales écrites en SmallTalk?
Je ne connais pas SmallTalk mais je connais un projet "célèbre" qui l'utilise : http://c2.com/cgi/wiki?ChryslerComprehensiveCompensation
La fameuse étude de cas pour le process XP. La fin de la page surtout est instructive, le projet ayant été "terminated" (pour des raisons 'externes' semble-t-il). Mais bien sûr, il y a des exemples d'applis en SmallTalk: http://wiki.cs.uiuc.edu/VisualWorks/Commercial+projects+that+use+Smalltalk On en trouvera également pour VisualBasic et surtout tous les languages de scripts interprétés - et déployées à plus large échelle.
Effectivement, si le but d'un projet est seulement d'assembler et de faire intéragir des composants préfabriqués (et que la plupart de ces composants existent sous une forme acceptable) il est judicieux d'envisager les alternatives au C++ -- peut-être AMHA surtout les solutions interprétées (Perl, Python et PHP sont ceux que j'utilise dernièrement).
Pour ce qui est des lambdas, je reste circonspect - quant à leur réelle utilité dans des cas simples
Gain de lisibilité, facilité de maintenance, moins de risque de bug.
// with boost::lambda for_each( v.begin(), v.end(), _1 *= 3 );
- quant à leur lisibilité dans des cas complexes
C'est pour ça qu'il y a bien des débats quant à la notation à implémenter dans C++ 0x...
Les raisons techniques qui font que ce code est écrit en C++ se résument souvent à un langage compilé (le C) et facile à lire (le ++)
Drôle de définition très personelle du C++ ;)
Plus un constat qu'une définition :-/
Suis essentiellement d'accord sur le constat -- bien qu'il m'ait été donné de voir des horreurs en C++ également -- pour autant qu'il ne s'agissait pas d'une comparaison entre o.f() et f(o) , mas de macros contre fonctions-inline/..., qsort contre sort, etc. ;) Mais je trouvais également ce constat très réducteur, car si lisibilité et compilation sont les seuls objectifs, sans doute Delphi devrait-il être envisagé. (J'ai personellement eu à pâtir du choix de Delphi par des prédécesseurs, pour une appli qui aurait dû être écrite en C++ pour bien d'autres raisons...).
Bon week-end, Ivan -- http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
"Olivier Azeau" <read.my.name.and.email.to.firstname@lastname.com> wrote in
message news:jT2Nd.20674$Of5.13684@nntpserver.swip.net...
Ivan Vecerina wrote:
"Olivier Azeau" <read.my.name.and.email.to.firstname@lastname.com> wrote
in message news:ITTMd.20578$Of5.13573@nntpserver.swip.net...
Qu'est-ce qui définit "souvent" ? (qui finalement n'est qu'un synonyme de
"la plupart")
Souvent ici est un très doux euphémisme.
Voir ma réponse à Alain Naigeon pour voir ce que signifie
le "tout-objet et tout-dynamique" dans un language comme SmallTalk.
Peux-tu me citer quelques applications commerciales
écrites en SmallTalk?
Je ne connais pas SmallTalk mais je connais un projet "célèbre" qui
l'utilise : http://c2.com/cgi/wiki?ChryslerComprehensiveCompensation
La fameuse étude de cas pour le process XP. La fin de la page surtout
est instructive, le projet ayant été "terminated" (pour des raisons
'externes' semble-t-il).
Mais bien sûr, il y a des exemples d'applis en SmallTalk:
http://wiki.cs.uiuc.edu/VisualWorks/Commercial+projects+that+use+Smalltalk
On en trouvera également pour VisualBasic et surtout tous les languages
de scripts interprétés - et déployées à plus large échelle.
Effectivement, si le but d'un projet est seulement d'assembler et de
faire intéragir des composants préfabriqués (et que la plupart de
ces composants existent sous une forme acceptable) il est judicieux
d'envisager les alternatives au C++ -- peut-être AMHA surtout les
solutions interprétées (Perl, Python et PHP sont ceux que j'utilise
dernièrement).
Pour ce qui est des lambdas, je reste circonspect
- quant à leur réelle utilité dans des cas simples
Gain de lisibilité, facilité de maintenance, moins de risque de bug.
// with boost::lambda
for_each( v.begin(), v.end(), _1 *= 3 );
- quant à leur lisibilité dans des cas complexes
C'est pour ça qu'il y a bien des débats quant à la notation à
implémenter dans C++ 0x...
Les raisons techniques qui font que ce code est écrit en C++
se résument souvent à un langage compilé (le C) et facile à lire (le ++)
Drôle de définition très personelle du C++ ;)
Plus un constat qu'une définition :-/
Suis essentiellement d'accord sur le constat -- bien qu'il m'ait
été donné de voir des horreurs en C++ également -- pour autant
qu'il ne s'agissait pas d'une comparaison entre o.f() et f(o) ,
mas de macros contre fonctions-inline/..., qsort contre sort, etc.
;)
Mais je trouvais également ce constat très réducteur, car si
lisibilité et compilation sont les seuls objectifs, sans doute
Delphi devrait-il être envisagé. (J'ai personellement eu à
pâtir du choix de Delphi par des prédécesseurs, pour une appli
qui aurait dû être écrite en C++ pour bien d'autres raisons...).
Bon week-end,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
"Olivier Azeau" wrote in message news:jT2Nd.20674$
Ivan Vecerina wrote:
"Olivier Azeau" wrote in message news:ITTMd.20578$
Qu'est-ce qui définit "souvent" ? (qui finalement n'est qu'un synonyme de "la plupart")
Souvent ici est un très doux euphémisme. Voir ma réponse à Alain Naigeon pour voir ce que signifie le "tout-objet et tout-dynamique" dans un language comme SmallTalk. Peux-tu me citer quelques applications commerciales écrites en SmallTalk?
Je ne connais pas SmallTalk mais je connais un projet "célèbre" qui l'utilise : http://c2.com/cgi/wiki?ChryslerComprehensiveCompensation
La fameuse étude de cas pour le process XP. La fin de la page surtout est instructive, le projet ayant été "terminated" (pour des raisons 'externes' semble-t-il). Mais bien sûr, il y a des exemples d'applis en SmallTalk: http://wiki.cs.uiuc.edu/VisualWorks/Commercial+projects+that+use+Smalltalk On en trouvera également pour VisualBasic et surtout tous les languages de scripts interprétés - et déployées à plus large échelle.
Effectivement, si le but d'un projet est seulement d'assembler et de faire intéragir des composants préfabriqués (et que la plupart de ces composants existent sous une forme acceptable) il est judicieux d'envisager les alternatives au C++ -- peut-être AMHA surtout les solutions interprétées (Perl, Python et PHP sont ceux que j'utilise dernièrement).
Pour ce qui est des lambdas, je reste circonspect - quant à leur réelle utilité dans des cas simples
Gain de lisibilité, facilité de maintenance, moins de risque de bug.
// with boost::lambda for_each( v.begin(), v.end(), _1 *= 3 );
- quant à leur lisibilité dans des cas complexes
C'est pour ça qu'il y a bien des débats quant à la notation à implémenter dans C++ 0x...
Les raisons techniques qui font que ce code est écrit en C++ se résument souvent à un langage compilé (le C) et facile à lire (le ++)
Drôle de définition très personelle du C++ ;)
Plus un constat qu'une définition :-/
Suis essentiellement d'accord sur le constat -- bien qu'il m'ait été donné de voir des horreurs en C++ également -- pour autant qu'il ne s'agissait pas d'une comparaison entre o.f() et f(o) , mas de macros contre fonctions-inline/..., qsort contre sort, etc. ;) Mais je trouvais également ce constat très réducteur, car si lisibilité et compilation sont les seuls objectifs, sans doute Delphi devrait-il être envisagé. (J'ai personellement eu à pâtir du choix de Delphi par des prédécesseurs, pour une appli qui aurait dû être écrite en C++ pour bien d'autres raisons...).
Bon week-end, Ivan -- http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
Olivier Azeau
Gabriel Dos Reis wrote:
Olivier Azeau writes:
| Alain Naigeon wrote: | > "Ivan Vecerina" a écrit dans le | > message news: cu1rmc$13o$ | > | >>Le C++ a intégré la programmation objet au C, mais sous une | >>forme "light" et peu couteuse en performance. Fonctions virtuelles | >>pour le polymorphisme, et un rudiment d'embryon d'introspection | >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk. | > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas | > mal | > de temps après les débuts. Et je me souviens de certains arguments : | > pourquoi voulez-vous connaître le type d'un objet à l'exécution, | > puique justement les fonctions virtuelles vous permettent de ne pas vous | > en soucier... | | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage. Un peu comme les concepts dans mon premier post : on prend un outil inconnu et on écrit le premier truc qui passe par la tête et que l'on trouve compréhensible car "ressemblant" à ce que l'on connait déjà par ailleurs (un switch, un héritage, ...) De l'utilisation de nouveaux outils par "mimétisme" en quelque sorte.
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
| Alain Naigeon wrote:
| > "Ivan Vecerina" <INVALID_use_webform_instead@vecerina.com> a écrit dans le
| > message news: cu1rmc$13o$1@news.hispeed.ch...
| >
| >>Le C++ a intégré la programmation objet au C, mais sous une
| >>forme "light" et peu couteuse en performance. Fonctions virtuelles
| >>pour le polymorphisme, et un rudiment d'embryon d'introspection
| >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk.
| > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas
| > mal
| > de temps après les débuts. Et je me souviens de certains arguments :
| > pourquoi voulez-vous connaître le type d'un objet à l'exécution,
| > puique justement les fonctions virtuelles vous permettent de ne pas vous
| > en soucier...
|
| D'ailleurs "typeid()" n'est quasiment pas utilisé.
|
| Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur
| ce genre de code :
| | A *a = monObjet();
| | if( dynamic_cast<B*>(a) != NULL ) {
| | faireCeci();
| | } else if( dynamic_cast<C*>(a) != NULL ) {
| | faireCela();
| | } else if( dynamic_cast<D*>(a) != NULL ) {
| | faireCeciEtCela();
| | }
| avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même
s'il en montre l'utilité dans certains cas (voir son bouquin). Mais
cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A.
Mais cela reste aussi représentatif de ce que la majorité fait quand on
rajoute des notions dans un langage.
Un peu comme les concepts dans mon premier post : on prend un outil
inconnu et on écrit le premier truc qui passe par la tête et que l'on
trouve compréhensible car "ressemblant" à ce que l'on connait déjà par
ailleurs (un switch, un héritage, ...)
De l'utilisation de nouveaux outils par "mimétisme" en quelque sorte.
Par exemple, j'aurais tendance à privilégier une approche basée
sur « Visitor Design Pattern » qui sera souvent plus propre et
efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
(Visitor Design Pattern est aux types ce que switch() est aux
expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu
décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter
dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter
directement ces méthodes dans les classes de la hiérarchie ?")
| Alain Naigeon wrote: | > "Ivan Vecerina" a écrit dans le | > message news: cu1rmc$13o$ | > | >>Le C++ a intégré la programmation objet au C, mais sous une | >>forme "light" et peu couteuse en performance. Fonctions virtuelles | >>pour le polymorphisme, et un rudiment d'embryon d'introspection | >>avec typeinfo -- pas comparable à l'OO dynamique pur du SmallTalk. | > Ok, et merci pour les précisions. Ceci dit, le typeinfo est venu pas | > mal | > de temps après les débuts. Et je me souviens de certains arguments : | > pourquoi voulez-vous connaître le type d'un objet à l'exécution, | > puique justement les fonctions virtuelles vous permettent de ne pas vous | > en soucier... | | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage. Un peu comme les concepts dans mon premier post : on prend un outil inconnu et on écrit le premier truc qui passe par la tête et que l'on trouve compréhensible car "ressemblant" à ce que l'on connait déjà par ailleurs (un switch, un héritage, ...) De l'utilisation de nouveaux outils par "mimétisme" en quelque sorte.
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
Jean-Marc Bourguet
Olivier Azeau writes:
| | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A. C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la "majorité" avec un langage. Même quelqu'un travaillant comme consultant, avec donc a priori plus de variété de projets et d'environnement que des employés permanents, a un certain biais d'une part sur ses domaines d'expertises, d'autre part sur une auto-sélection de clients qui vont le choisir parce qu'il pense comme eux.
Tout ça pour écrire que ça ne fait pas partie des nombreuses horreurs que j'ai vues.
[...]
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur connait toute la hiérarchie potentiellement visitée.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais finir par penser que mon environnement est meilleur que je ne le pensais :-)
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
| | D'ailleurs "typeid()" n'est quasiment pas utilisé.
| | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur
| ce genre de code :
| | A *a = monObjet();
| | if( dynamic_cast<B*>(a) != NULL ) {
| | faireCeci();
| | } else if( dynamic_cast<C*>(a) != NULL ) {
| | faireCela();
| | } else if( dynamic_cast<D*>(a) != NULL ) {
| | faireCeciEtCela();
| | }
| avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même
s'il en montre l'utilité dans certains cas (voir son bouquin). Mais
cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais
cela reste aussi représentatif de ce que la majorité fait
quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la
"majorité" avec un langage. Même quelqu'un travaillant
comme consultant, avec donc a priori plus de variété de
projets et d'environnement que des employés permanents, a un
certain biais d'une part sur ses domaines d'expertises,
d'autre part sur une auto-sélection de clients qui vont le
choisir parce qu'il pense comme eux.
Tout ça pour écrire que ça ne fait pas partie des nombreuses
horreurs que j'ai vues.
[...]
Par exemple, j'aurais tendance à privilégier une approche basée
sur « Visitor Design Pattern » qui sera souvent plus propre et
efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur
connait toute la hiérarchie potentiellement visitée.
(Visitor Design Pattern est aux types ce que switch()
est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce
pattern un peu décrié ("pourquoi rajouter une méthode
'accept' qui permet de rajouter dynamiquement des méthodes
sur la hiérarchie plutôt que de rajouter directement ces
méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais
finir par penser que mon environnement est meilleur que je
ne le pensais :-)
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
| | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A. C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la "majorité" avec un langage. Même quelqu'un travaillant comme consultant, avec donc a priori plus de variété de projets et d'environnement que des employés permanents, a un certain biais d'une part sur ses domaines d'expertises, d'autre part sur une auto-sélection de clients qui vont le choisir parce qu'il pense comme eux.
Tout ça pour écrire que ça ne fait pas partie des nombreuses horreurs que j'ai vues.
[...]
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur connait toute la hiérarchie potentiellement visitée.
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais finir par penser que mon environnement est meilleur que je ne le pensais :-)
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Olivier Azeau
Jean-Marc Bourguet wrote:
Olivier Azeau writes:
| | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A. C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la "majorité" avec un langage. Même quelqu'un travaillant comme consultant, avec donc a priori plus de variété de projets et d'environnement que des employés permanents, a un certain biais d'une part sur ses domaines d'expertises, d'autre part sur une auto-sélection de clients qui vont le choisir parce qu'il pense comme eux.
"Qui se ressemble s'assemble" c'est ça ?
Il y avait en fait peut être une ambiguité sémantique. Je n'ai rencontré un code comme ci-dessus que dans peu de cas (avec quand même une fois il y a longtemps où un "expert" me certifiait que c'était *la* façon de faire). J'ai juste voulu dire que les idiomatismes ont une longue durée de vie.
Tout ça pour écrire que ça ne fait pas partie des nombreuses horreurs que j'ai vues.
Pour moi la question n'est pas tant de savoir si c'est horrible mais dans quelle mesure on peut le justifier. Un peu comme :
std::vector<int> v; for( int i=0; i<v.length(); ++i ) x += v[i];
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur connait toute la hiérarchie potentiellement visitée.
"Couplage unidirectionnel" c'est mieux ?
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais finir par penser que mon environnement est meilleur que je ne le pensais :-)
| | D'ailleurs "typeid()" n'est quasiment pas utilisé.
| | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur
| ce genre de code :
| | A *a = monObjet();
| | if( dynamic_cast<B*>(a) != NULL ) {
| | faireCeci();
| | } else if( dynamic_cast<C*>(a) != NULL ) {
| | faireCela();
| | } else if( dynamic_cast<D*>(a) != NULL ) {
| | faireCeciEtCela();
| | }
| avec, bien sûr, B, C, et D qui héritent de A.
C'est le genre de code que l'auteur de la RTTI voulait minimiser, même
s'il en montre l'utilité dans certains cas (voir son bouquin). Mais
cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais
cela reste aussi représentatif de ce que la majorité fait
quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la
"majorité" avec un langage. Même quelqu'un travaillant
comme consultant, avec donc a priori plus de variété de
projets et d'environnement que des employés permanents, a un
certain biais d'une part sur ses domaines d'expertises,
d'autre part sur une auto-sélection de clients qui vont le
choisir parce qu'il pense comme eux.
"Qui se ressemble s'assemble" c'est ça ?
Il y avait en fait peut être une ambiguité sémantique.
Je n'ai rencontré un code comme ci-dessus que dans peu de cas (avec
quand même une fois il y a longtemps où un "expert" me certifiait que
c'était *la* façon de faire). J'ai juste voulu dire que les idiomatismes
ont une longue durée de vie.
Tout ça pour écrire que ça ne fait pas partie des nombreuses
horreurs que j'ai vues.
Pour moi la question n'est pas tant de savoir si c'est horrible mais
dans quelle mesure on peut le justifier.
Un peu comme :
std::vector<int> v;
for( int i=0; i<v.length(); ++i )
x += v[i];
Par exemple, j'aurais tendance à privilégier une approche basée
sur « Visitor Design Pattern » qui sera souvent plus propre et
efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur
connait toute la hiérarchie potentiellement visitée.
"Couplage unidirectionnel" c'est mieux ?
(Visitor Design Pattern est aux types ce que switch()
est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce
pattern un peu décrié ("pourquoi rajouter une méthode
'accept' qui permet de rajouter dynamiquement des méthodes
sur la hiérarchie plutôt que de rajouter directement ces
méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais
finir par penser que mon environnement est meilleur que je
ne le pensais :-)
| | D'ailleurs "typeid()" n'est quasiment pas utilisé. | | Par contre, il m'est arrivé, plus souvent qu'à mon tour, de tomber sur | ce genre de code : | | A *a = monObjet(); | | if( dynamic_cast<B*>(a) != NULL ) { | | faireCeci(); | | } else if( dynamic_cast<C*>(a) != NULL ) { | | faireCela(); | | } else if( dynamic_cast<D*>(a) != NULL ) { | | faireCeciEtCela(); | | } | avec, bien sûr, B, C, et D qui héritent de A. C'est le genre de code que l'auteur de la RTTI voulait minimiser, même s'il en montre l'utilité dans certains cas (voir son bouquin). Mais cela reste quand même dans la catégorie « brittle and gastly codes » :-)
Oui... Surtout quand le voit dans une méthode de A. Mais cela reste aussi représentatif de ce que la majorité fait quand on rajoute des notions dans un langage.
Je me demande comment on peut savoir ce que fait la "majorité" avec un langage. Même quelqu'un travaillant comme consultant, avec donc a priori plus de variété de projets et d'environnement que des employés permanents, a un certain biais d'une part sur ses domaines d'expertises, d'autre part sur une auto-sélection de clients qui vont le choisir parce qu'il pense comme eux.
"Qui se ressemble s'assemble" c'est ça ?
Il y avait en fait peut être une ambiguité sémantique. Je n'ai rencontré un code comme ci-dessus que dans peu de cas (avec quand même une fois il y a longtemps où un "expert" me certifiait que c'était *la* façon de faire). J'ai juste voulu dire que les idiomatismes ont une longue durée de vie.
Tout ça pour écrire que ça ne fait pas partie des nombreuses horreurs que j'ai vues.
Pour moi la question n'est pas tant de savoir si c'est horrible mais dans quelle mesure on peut le justifier. Un peu comme :
std::vector<int> v; for( int i=0; i<v.length(); ++i ) x += v[i];
Par exemple, j'aurais tendance à privilégier une approche basée sur « Visitor Design Pattern » qui sera souvent plus propre et efficace qu'une série de if-else + dynamic_cast.
Et, surtout, permet le couplage faible.
Couplage faible? Avec la technique classique, tout visiteur connait toute la hiérarchie potentiellement visitée.
"Couplage unidirectionnel" c'est mieux ?
(Visitor Design Pattern est aux types ce que switch() est aux expressions entière constantes).
Tout à fait, même si j'essaie de ne pas en abuser de ce pattern un peu décrié ("pourquoi rajouter une méthode 'accept' qui permet de rajouter dynamiquement des méthodes sur la hiérarchie plutôt que de rajouter directement ces méthodes dans les classes de la hiérarchie ?")
Encore une attitude que je n'ai pas rencontrée. Je vais finir par penser que mon environnement est meilleur que je ne le pensais :-)
Quelle attitude ?
Gabriel Dos Reis
Olivier Azeau writes:
[...]
| Mais cela reste aussi représentatif de ce que la majorité fait quand | on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens contre Programmeur Machiavel, mais contre Murphy. Cela est d'une certaine manière contraire à des langages comme Java ou clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle peut être mal utilisée est très non-C++. En C++, la question est rarememt si cela peut être mal utilisé, mais plutôt si cela est utile et que le bénéfice en vaut le coût.
| Mais cela reste aussi représentatif de ce que la majorité fait quand
| on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée
et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens
contre Programmeur Machiavel, mais contre Murphy.
Cela est d'une certaine manière contraire à des langages comme Java ou
clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle
peut être mal utilisée est très non-C++. En C++, la question est
rarememt si cela peut être mal utilisé, mais plutôt si cela est utile
et que le bénéfice en vaut le coût.
| Mais cela reste aussi représentatif de ce que la majorité fait quand | on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens contre Programmeur Machiavel, mais contre Murphy. Cela est d'une certaine manière contraire à des langages comme Java ou clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle peut être mal utilisée est très non-C++. En C++, la question est rarememt si cela peut être mal utilisé, mais plutôt si cela est utile et que le bénéfice en vaut le coût.
-- Gaby
Olivier Azeau
Gabriel Dos Reis wrote:
Olivier Azeau writes:
[...]
| Mais cela reste aussi représentatif de ce que la majorité fait quand | on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens contre Programmeur Machiavel, mais contre Murphy.
Qui parle de Machiavel ? En l'occurrence, les "mauvaises utilisations", comme tu les appelles, sont faites de bonne foi.
Cela est d'une certaine manière contraire à des langages comme Java ou clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle peut être mal utilisée est très non-C++. En C++, la question est rarememt si cela peut être mal utilisé, mais plutôt si cela est utile et que le bénéfice en vaut le coût.
Tout à fait. Je ne sais plus qui dans ce thread a mentionné que, à la longue, les bonnes idées en termes d'évolution du langage finissent toujours par être payantes. D'où la deuxième question qui peut être "le coût est-il négligeable ?" mais à laquelle je préfère "que peut-on faire pour minimiser ce coût ?" -- sachant que "Java et clones" seront là, tout près, et exerceront une grande influence.
| Mais cela reste aussi représentatif de ce que la majorité fait quand
| on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée
et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens
contre Programmeur Machiavel, mais contre Murphy.
Qui parle de Machiavel ? En l'occurrence, les "mauvaises utilisations",
comme tu les appelles, sont faites de bonne foi.
Cela est d'une certaine manière contraire à des langages comme Java ou
clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle
peut être mal utilisée est très non-C++. En C++, la question est
rarememt si cela peut être mal utilisé, mais plutôt si cela est utile
et que le bénéfice en vaut le coût.
Tout à fait. Je ne sais plus qui dans ce thread a mentionné que, à la
longue, les bonnes idées en termes d'évolution du langage finissent
toujours par être payantes.
D'où la deuxième question qui peut être "le coût est-il négligeable ?"
mais à laquelle je préfère "que peut-on faire pour minimiser ce coût ?"
-- sachant que "Java et clones" seront là, tout près, et exerceront une
grande influence.
| Mais cela reste aussi représentatif de ce que la majorité fait quand | on rajoute des notions dans un langage.
N'importe quelle fonctionnalité existante ou future peut être abusée et mal utilisée. La pholosophie de C++ n'est pas de protéger les gens contre Programmeur Machiavel, mais contre Murphy.
Qui parle de Machiavel ? En l'occurrence, les "mauvaises utilisations", comme tu les appelles, sont faites de bonne foi.
Cela est d'une certaine manière contraire à des langages comme Java ou clones. Arguer aujourd'hui contre une fonctionnalité C++ parce qu'elle peut être mal utilisée est très non-C++. En C++, la question est rarememt si cela peut être mal utilisé, mais plutôt si cela est utile et que le bénéfice en vaut le coût.
Tout à fait. Je ne sais plus qui dans ce thread a mentionné que, à la longue, les bonnes idées en termes d'évolution du langage finissent toujours par être payantes. D'où la deuxième question qui peut être "le coût est-il négligeable ?" mais à laquelle je préfère "que peut-on faire pour minimiser ce coût ?" -- sachant que "Java et clones" seront là, tout près, et exerceront une grande influence.
kanze
Gabriel Dos Reis wrote:
writes:
[...]
| > Mais qu'il s'agisse de traitement d'image, de | > programmation graphique, de jeux, de systèmes temps-réel | > ou de programmation multi-process, je trouve réguilérement | > une place à la paramétrisation d'algorithmes ou de | > diverses classes.
| Quel rapport ? Quand les templates conviennent, on utilise | les templates. Quand l'héritage convient, on utilise | l'héritage. Les
Monsieur de la Palisse n'aurait pas dit le contraire.
Lui, peut-être pas, mais il semble qu'il y a une mode aujourd'hui à negliger l'héritage, parfois jusqu'au point de dire qu'il ne faut jamais s'en servir.
| deux sont là pour une raison, et c'est même plutôt rare que | leurs champs d'applications se récouvrent.
Ah bon. simple example, regarder comment la généricité est pratiquée dans des langages comme Java et autres et avant (peut-être encore aujourd'hui)
Quand j'écris du code en Java, je l'écris en Java. Essayer à faire du C++ en Java ne marche pas mieux que d'essayer à faire du Java en C++.
En ce qui concerne un équivalent aux templates en Java, ça lui manque (ou a manqué) pas mal. Alors, comme on dit : « when all you've got is a hammer, everything looks like a nail ». Mais c'est un problème assez répandu pourqu'il y avait des idiomes standard pour la résoudre.
avec C++ dans certains milieux par des autor-proclamés orienté objets. Mais hein.
Ça, j'avoue qu'il ne m'est jamais arrivé de voir ce problème en C++. Mais il faut dire que dans les milieux où j'ai travaillé, quand on cherchait quelqu'un pour faire du C++, on démandait à ce qu'il connaisse le C++. Non seulement le langage en tant que tel, mais aussi des idiomes consacrés du langage.
Je n'en ai vu qu'un cas de l'autre extrème, avec l'utilisation en surabondance des templates. Et même là, le problème n'était pas tellement qu'il utilisait des templates quand il aurait fallu l'héritage, mais qu'il s'est mis à développer dans son coin, avec la dernière version de g++, et qu'il ne s'est pas tenu compte du fait qu'il fallait que le code se compile avec VC++ 6.0 et Sun CC 4.2. (Ni, d'ailleur, que dans ce cas précis, on aurait pû tout générer avec une dizaines de lignes de AWK comme générateur externe. Faut pas abuser non plus.)
-- James Kanze GABI Software http://www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Gabriel Dos Reis wrote:
kanze@gabi-soft.fr writes:
[...]
| > Mais qu'il s'agisse de traitement d'image, de
| > programmation graphique, de jeux, de systèmes temps-réel
| > ou de programmation multi-process, je trouve réguilérement
| > une place à la paramétrisation d'algorithmes ou de
| > diverses classes.
| Quel rapport ? Quand les templates conviennent, on utilise
| les templates. Quand l'héritage convient, on utilise
| l'héritage. Les
Monsieur de la Palisse n'aurait pas dit le contraire.
Lui, peut-être pas, mais il semble qu'il y a une mode
aujourd'hui à negliger l'héritage, parfois jusqu'au point de
dire qu'il ne faut jamais s'en servir.
| deux sont là pour une raison, et c'est même plutôt rare que
| leurs champs d'applications se récouvrent.
Ah bon. simple example, regarder comment la généricité est
pratiquée dans des langages comme Java et autres et avant
(peut-être encore aujourd'hui)
Quand j'écris du code en Java, je l'écris en Java. Essayer à
faire du C++ en Java ne marche pas mieux que d'essayer à faire
du Java en C++.
En ce qui concerne un équivalent aux templates en Java, ça lui
manque (ou a manqué) pas mal. Alors, comme on dit : « when all
you've got is a hammer, everything looks like a nail ». Mais
c'est un problème assez répandu pourqu'il y avait des idiomes
standard pour la résoudre.
avec C++ dans certains milieux par des autor-proclamés orienté
objets. Mais hein.
Ça, j'avoue qu'il ne m'est jamais arrivé de voir ce problème en
C++. Mais il faut dire que dans les milieux où j'ai travaillé,
quand on cherchait quelqu'un pour faire du C++, on démandait à
ce qu'il connaisse le C++. Non seulement le langage en tant que
tel, mais aussi des idiomes consacrés du langage.
Je n'en ai vu qu'un cas de l'autre extrème, avec l'utilisation
en surabondance des templates. Et même là, le problème n'était
pas tellement qu'il utilisait des templates quand il aurait
fallu l'héritage, mais qu'il s'est mis à développer dans son
coin, avec la dernière version de g++, et qu'il ne s'est pas
tenu compte du fait qu'il fallait que le code se compile avec
VC++ 6.0 et Sun CC 4.2. (Ni, d'ailleur, que dans ce cas précis,
on aurait pû tout générer avec une dizaines de lignes de AWK
comme générateur externe. Faut pas abuser non plus.)
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
| > Mais qu'il s'agisse de traitement d'image, de | > programmation graphique, de jeux, de systèmes temps-réel | > ou de programmation multi-process, je trouve réguilérement | > une place à la paramétrisation d'algorithmes ou de | > diverses classes.
| Quel rapport ? Quand les templates conviennent, on utilise | les templates. Quand l'héritage convient, on utilise | l'héritage. Les
Monsieur de la Palisse n'aurait pas dit le contraire.
Lui, peut-être pas, mais il semble qu'il y a une mode aujourd'hui à negliger l'héritage, parfois jusqu'au point de dire qu'il ne faut jamais s'en servir.
| deux sont là pour une raison, et c'est même plutôt rare que | leurs champs d'applications se récouvrent.
Ah bon. simple example, regarder comment la généricité est pratiquée dans des langages comme Java et autres et avant (peut-être encore aujourd'hui)
Quand j'écris du code en Java, je l'écris en Java. Essayer à faire du C++ en Java ne marche pas mieux que d'essayer à faire du Java en C++.
En ce qui concerne un équivalent aux templates en Java, ça lui manque (ou a manqué) pas mal. Alors, comme on dit : « when all you've got is a hammer, everything looks like a nail ». Mais c'est un problème assez répandu pourqu'il y avait des idiomes standard pour la résoudre.
avec C++ dans certains milieux par des autor-proclamés orienté objets. Mais hein.
Ça, j'avoue qu'il ne m'est jamais arrivé de voir ce problème en C++. Mais il faut dire que dans les milieux où j'ai travaillé, quand on cherchait quelqu'un pour faire du C++, on démandait à ce qu'il connaisse le C++. Non seulement le langage en tant que tel, mais aussi des idiomes consacrés du langage.
Je n'en ai vu qu'un cas de l'autre extrème, avec l'utilisation en surabondance des templates. Et même là, le problème n'était pas tellement qu'il utilisait des templates quand il aurait fallu l'héritage, mais qu'il s'est mis à développer dans son coin, avec la dernière version de g++, et qu'il ne s'est pas tenu compte du fait qu'il fallait que le code se compile avec VC++ 6.0 et Sun CC 4.2. (Ni, d'ailleur, que dans ce cas précis, on aurait pû tout générer avec une dizaines de lignes de AWK comme générateur externe. Faut pas abuser non plus.)
-- James Kanze GABI Software http://www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
kanze
Ivan Vecerina wrote:
| wrote in message |news: |Ivan Vecerina wrote: |> "James Kanze" wrote in message |> news:42028b18$0$24299$
|> Mais qu'il s'agisse de traitement d'image, de programmation |> graphique, de jeux, de systèmes temps-réel ou de |> programmation multi-process, je trouve réguilérement une |> place à la paramétrisation d'algorithmes ou de diverses |> classes.
|Quel rapport ? Quand les templates conviennent, on utilise |les templates. Quand l'héritage convient, on utilise |l'héritage. Les deux sont là pour une raison, et c'est même |plutôt rare que leurs champs d'applications se récouvrent.
On ne perd certainement pas en puissance et en flexibilité en faisant du tout-object et tout-dynamique.
Bien sûr que si. Et comment. Il y a des choses qui ne se laisse pas exprimer, ou au moins dont l'expression est beaucoup plus complexe, avec l'héritage. Et vice-versa.
Cependant, même dans des applications banales, ceci a un coût souvent rédhibitoire.
Utiliser un outil mal-approprié est toujours très cher.
C'est pour pouvoir manipuler des données (relativement) brutes et pas tout-à-fait encapsulée derrière des objets et des messages que l'on doit se résoudre à avoir recours à d'autres formes de dispatching et de réutilisation de code.
D'après mes expériences : une très bonne encapsulation est essentielle si la performance risque d'être un problème. Parce que sans l'encapsulation, on est bloqué ; on ne peut plus faire des modifications nécessaires une fois que le profiler a montré où se trouve les problèmes.
Le résultat, en C++, est effectivement que l'on a des champs d'application relativement distincts pour les templates et les fonctions virtuelles/héritages.
Ce n'est pas un « résultat » de je ne sais pas quel problème de performance. C'est qu'il s'agit de deux outils différents, conçus pour résoudre des problèmes différents. Si tu as besoin de l'héritage et des fonctions virtuelles, il y a peu de chances que les templates font l'affaire, et vice versa. Et dans les rares cas où l'un ou l'autre peut servir... La seule fois que j'ai fait une mésure, les templates étaient plus rapide avec g++, et les fonctions virtuelles avec Sun CC (qui était aussi plus rapid globalement). Mais ça fait un moment, les versions (g++ 2.95.2 et Sun CC 4.2) que j'ai comparé ne sont plus du tout actuelle. C'est juste pour dire que la solution n'est pas si évidente qu'elle puisse semblait.
|> Pour ce qui est des accès disque (lecture ou écriture), je |> procède en général par memory-mapping (sous NT ou Unix). |> Ceci simplifie le code et permet au systèmes d'optimiser et |> de paralléliser les accès mémoire.
|Mais ça ne garantit rien. L'écriture n'est pas forcement |faite. C'est bon pour des choses « jettables », mais je n'ai |pas le droit d'informer le client que son ordre a été pris en |compte tant que je ne peux pas garantir pouvoir le récupérer, |même en cas de crash système.
Qu'il s'agisse de memory-mapping ou d'écriture d'une séquence d'octets, là n'est pas la question. Sans flush il n'y a pas de garantie, ni dans un cas ni dans l'autre.
(Attention. Je crois que ton propos peut préter à la confusion. À ce niveau-ci, on parle plus volentiers de sync que de flush.)
Tout à fait. Sauf qu'il y a une option d'open ou de fcntl qui fait que toute écriture est synchronisée. Tandis que s'assurer la synchronisation avec mmap est plus complex. (Je parle de Unix ici, parce que je n'ai pas la moindre idée comment ça se passe sous Windows. Je suppose qu'une persistance robuste est possible sous Windows, mais je n'ai pas la moindre idée comment y arriver.)
Et c'est la synchronisation, évidemment, qui coûte les dix millisecondes.
|> > Dans les applications que j'ai vu, le goulot a prèsque |> > toujours été l'écriture disque.
Sur quoi j'ai mentionné un autre genre d'applications... la réponse pourrait presque être amusante:
|Si tu régardes autour de toi, tu verras que la plupart des |programmes font bien peu de choses, en somme.
Qui ne voit pas assez loin ?
Regarde autour de toi. Pas seulement au boulot, où tu travailles peut-être dans un domaine où la performance CPU est importante, mais plus généralement. Les ordinateurs dans ta voiture, par exemple. Les serveurs de page web (ou il y a certainement quelques un où la performance est importante, mais combien par rapport à ceux qui ne font que de resservir des pages tout faites ou gérer un chariot d'achat). Les ordinateurs de l'état (je suppose que tu paies des impots, ou que tu as un permit de conduire), les ordinateurs du boulanger (qui s'appelle pas toujours par le nom d'ordinateur), ou du grande surface.
Qu'est-ce qui définit "la plupart" ?
En effet, plusieurs définitions sont possible. Si on ne considère que le nombre d'instances des programmes qui tournent, par exemple, le fait est trivialement vrai (plus de 90% du marché des processeurs concerne les systèmes embarqués). Mais une programme qui tourne sur 10 millions d'appareils, est-ce qu'on le compte une fois, ou 10 millions ?
Si on parle de nombre de programmes différents, c'est plus difficile à chiffrer. J'avoue là que je prends un point de vue un peu « intéressé » -- je régarde les offres d'emploi et les démandes pour des programmeurs. Là, je peux dire qu'en filtrant sur C++ (et éventuellement des critères géographiques très largues), le nombre d'offres où la performance CPU du programme serait une considération est extremement faible. Mais peut-être des offres de ce genre se traitent sur un autre marché, peut-être entre-amis, et que je ne les vois pas.
|Tu fais donc beaucoup de calcul pour peu d'affichage, sur de |grands jeux de données en mémoire. Ce sont typiquement des |applications numériques où c'est le cas, ou peut-être les |jeux. Mais ce n'est pas typique de beaucoup de programmeurs ; |si je régarde dans les démandes d'emploi, par exemple, il y a |fort peu de démande pour les matheux, en dehors des banques |(et les programmes de marché sont un peu spéciaux comme |applications numériques, parce qu'ils ne traitent en général |qu'un petit jeu de données, en lui appliquant des formules on |ne peut plus compliquées).
Je suis impressionné par la portée de l'interprétation et du jugement que vous vous permettez de faire. Le "matheux qui fait beaucoup de calcul pour peu d'affichage, sans perspective professionnelle sinon dans le bancaire pour faire des trucs très compliqués avec peu de données" avait jusqu'à présent une certaine considération pour vous.
J'ai de la considération pour eux, aussi. Je crois même que ce qu'ils font est important. Mais je crois aussi qu'ils sont une faible minorité des programmeurs.
Comme j'ai dit, je ne vois pas beaucoup d'offres d'emploi dans ces domaines. Ça ne veut pas dire que ce qu'ils font est sans importance ; je soupçonne même que c'est globalement plus important que ce que font la plupart des programmes.
Mais ce n'était pas mon propos. Tout ce que j'ai dit, c'est que la plupart des programmeurs n'en sont pas directement concernés par la différence en vitesse entre un appel virtuel et un appel non-virtuel.
-- James Kanze GABI Software http://www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Ivan Vecerina wrote:
|<kanze@gabi-soft.fr> wrote in message
|news:1107507856.068380.121410@l41g2000cwc.googlegroups.com...
|Ivan Vecerina wrote:
|> "James Kanze" <kanze@none> wrote in message
|> news:42028b18$0$24299$636a15ce@news.free.fr...
|> Mais qu'il s'agisse de traitement d'image, de programmation
|> graphique, de jeux, de systèmes temps-réel ou de
|> programmation multi-process, je trouve réguilérement une
|> place à la paramétrisation d'algorithmes ou de diverses
|> classes.
|Quel rapport ? Quand les templates conviennent, on utilise
|les templates. Quand l'héritage convient, on utilise
|l'héritage. Les deux sont là pour une raison, et c'est même
|plutôt rare que leurs champs d'applications se récouvrent.
On ne perd certainement pas en puissance et en flexibilité en
faisant du tout-object et tout-dynamique.
Bien sûr que si. Et comment. Il y a des choses qui ne se laisse
pas exprimer, ou au moins dont l'expression est beaucoup plus
complexe, avec l'héritage. Et vice-versa.
Cependant, même dans des applications banales, ceci a un coût
souvent rédhibitoire.
Utiliser un outil mal-approprié est toujours très cher.
C'est pour pouvoir manipuler des données (relativement) brutes
et pas tout-à-fait encapsulée derrière des objets et des
messages que l'on doit se résoudre à avoir recours à d'autres
formes de dispatching et de réutilisation de code.
D'après mes expériences : une très bonne encapsulation est
essentielle si la performance risque d'être un problème. Parce
que sans l'encapsulation, on est bloqué ; on ne peut plus faire
des modifications nécessaires une fois que le profiler a montré
où se trouve les problèmes.
Le résultat, en C++, est effectivement que l'on a des champs
d'application relativement distincts pour les templates et les
fonctions virtuelles/héritages.
Ce n'est pas un « résultat » de je ne sais pas quel problème de
performance. C'est qu'il s'agit de deux outils différents,
conçus pour résoudre des problèmes différents. Si tu as besoin
de l'héritage et des fonctions virtuelles, il y a peu de chances
que les templates font l'affaire, et vice versa. Et dans les
rares cas où l'un ou l'autre peut servir... La seule fois que
j'ai fait une mésure, les templates étaient plus rapide avec
g++, et les fonctions virtuelles avec Sun CC (qui était aussi
plus rapid globalement). Mais ça fait un moment, les versions
(g++ 2.95.2 et Sun CC 4.2) que j'ai comparé ne sont plus du tout
actuelle. C'est juste pour dire que la solution n'est pas si
évidente qu'elle puisse semblait.
|> Pour ce qui est des accès disque (lecture ou écriture), je
|> procède en général par memory-mapping (sous NT ou Unix).
|> Ceci simplifie le code et permet au systèmes d'optimiser et
|> de paralléliser les accès mémoire.
|Mais ça ne garantit rien. L'écriture n'est pas forcement
|faite. C'est bon pour des choses « jettables », mais je n'ai
|pas le droit d'informer le client que son ordre a été pris en
|compte tant que je ne peux pas garantir pouvoir le récupérer,
|même en cas de crash système.
Qu'il s'agisse de memory-mapping ou d'écriture d'une séquence
d'octets, là n'est pas la question. Sans flush il n'y a pas de
garantie, ni dans un cas ni dans l'autre.
(Attention. Je crois que ton propos peut préter à la confusion.
À ce niveau-ci, on parle plus volentiers de sync que de flush.)
Tout à fait. Sauf qu'il y a une option d'open ou de fcntl qui
fait que toute écriture est synchronisée. Tandis que s'assurer
la synchronisation avec mmap est plus complex. (Je parle de Unix
ici, parce que je n'ai pas la moindre idée comment ça se passe
sous Windows. Je suppose qu'une persistance robuste est possible
sous Windows, mais je n'ai pas la moindre idée comment y
arriver.)
Et c'est la synchronisation, évidemment, qui coûte les dix
millisecondes.
|> > Dans les applications que j'ai vu, le goulot a prèsque
|> > toujours été l'écriture disque.
Sur quoi j'ai mentionné un autre genre d'applications... la
réponse pourrait presque être amusante:
|Si tu régardes autour de toi, tu verras que la plupart des
|programmes font bien peu de choses, en somme.
Qui ne voit pas assez loin ?
Regarde autour de toi. Pas seulement au boulot, où tu travailles
peut-être dans un domaine où la performance CPU est importante,
mais plus généralement. Les ordinateurs dans ta voiture, par
exemple. Les serveurs de page web (ou il y a certainement
quelques un où la performance est importante, mais combien par
rapport à ceux qui ne font que de resservir des pages tout
faites ou gérer un chariot d'achat). Les ordinateurs de l'état
(je suppose que tu paies des impots, ou que tu as un permit
de conduire), les ordinateurs du boulanger (qui s'appelle pas
toujours par le nom d'ordinateur), ou du grande surface.
Qu'est-ce qui définit "la plupart" ?
En effet, plusieurs définitions sont possible. Si on ne
considère que le nombre d'instances des programmes qui tournent,
par exemple, le fait est trivialement vrai (plus de 90% du
marché des processeurs concerne les systèmes embarqués). Mais
une programme qui tourne sur 10 millions d'appareils, est-ce
qu'on le compte une fois, ou 10 millions ?
Si on parle de nombre de programmes différents, c'est plus
difficile à chiffrer. J'avoue là que je prends un point de vue
un peu « intéressé » -- je régarde les offres d'emploi et les
démandes pour des programmeurs. Là, je peux dire qu'en filtrant
sur C++ (et éventuellement des critères géographiques très
largues), le nombre d'offres où la performance CPU du programme
serait une considération est extremement faible. Mais peut-être
des offres de ce genre se traitent sur un autre marché,
peut-être entre-amis, et que je ne les vois pas.
|Tu fais donc beaucoup de calcul pour peu d'affichage, sur de
|grands jeux de données en mémoire. Ce sont typiquement des
|applications numériques où c'est le cas, ou peut-être les
|jeux. Mais ce n'est pas typique de beaucoup de programmeurs ;
|si je régarde dans les démandes d'emploi, par exemple, il y a
|fort peu de démande pour les matheux, en dehors des banques
|(et les programmes de marché sont un peu spéciaux comme
|applications numériques, parce qu'ils ne traitent en général
|qu'un petit jeu de données, en lui appliquant des formules on
|ne peut plus compliquées).
Je suis impressionné par la portée de l'interprétation et du
jugement que vous vous permettez de faire. Le "matheux qui
fait beaucoup de calcul pour peu d'affichage, sans perspective
professionnelle sinon dans le bancaire pour faire des trucs
très compliqués avec peu de données" avait jusqu'à présent une
certaine considération pour vous.
J'ai de la considération pour eux, aussi. Je crois même que ce
qu'ils font est important. Mais je crois aussi qu'ils sont une
faible minorité des programmeurs.
Comme j'ai dit, je ne vois pas beaucoup d'offres d'emploi dans
ces domaines. Ça ne veut pas dire que ce qu'ils font est sans
importance ; je soupçonne même que c'est globalement plus
important que ce que font la plupart des programmes.
Mais ce n'était pas mon propos. Tout ce que j'ai dit, c'est que
la plupart des programmeurs n'en sont pas directement concernés
par la différence en vitesse entre un appel virtuel et un appel
non-virtuel.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
| wrote in message |news: |Ivan Vecerina wrote: |> "James Kanze" wrote in message |> news:42028b18$0$24299$
|> Mais qu'il s'agisse de traitement d'image, de programmation |> graphique, de jeux, de systèmes temps-réel ou de |> programmation multi-process, je trouve réguilérement une |> place à la paramétrisation d'algorithmes ou de diverses |> classes.
|Quel rapport ? Quand les templates conviennent, on utilise |les templates. Quand l'héritage convient, on utilise |l'héritage. Les deux sont là pour une raison, et c'est même |plutôt rare que leurs champs d'applications se récouvrent.
On ne perd certainement pas en puissance et en flexibilité en faisant du tout-object et tout-dynamique.
Bien sûr que si. Et comment. Il y a des choses qui ne se laisse pas exprimer, ou au moins dont l'expression est beaucoup plus complexe, avec l'héritage. Et vice-versa.
Cependant, même dans des applications banales, ceci a un coût souvent rédhibitoire.
Utiliser un outil mal-approprié est toujours très cher.
C'est pour pouvoir manipuler des données (relativement) brutes et pas tout-à-fait encapsulée derrière des objets et des messages que l'on doit se résoudre à avoir recours à d'autres formes de dispatching et de réutilisation de code.
D'après mes expériences : une très bonne encapsulation est essentielle si la performance risque d'être un problème. Parce que sans l'encapsulation, on est bloqué ; on ne peut plus faire des modifications nécessaires une fois que le profiler a montré où se trouve les problèmes.
Le résultat, en C++, est effectivement que l'on a des champs d'application relativement distincts pour les templates et les fonctions virtuelles/héritages.
Ce n'est pas un « résultat » de je ne sais pas quel problème de performance. C'est qu'il s'agit de deux outils différents, conçus pour résoudre des problèmes différents. Si tu as besoin de l'héritage et des fonctions virtuelles, il y a peu de chances que les templates font l'affaire, et vice versa. Et dans les rares cas où l'un ou l'autre peut servir... La seule fois que j'ai fait une mésure, les templates étaient plus rapide avec g++, et les fonctions virtuelles avec Sun CC (qui était aussi plus rapid globalement). Mais ça fait un moment, les versions (g++ 2.95.2 et Sun CC 4.2) que j'ai comparé ne sont plus du tout actuelle. C'est juste pour dire que la solution n'est pas si évidente qu'elle puisse semblait.
|> Pour ce qui est des accès disque (lecture ou écriture), je |> procède en général par memory-mapping (sous NT ou Unix). |> Ceci simplifie le code et permet au systèmes d'optimiser et |> de paralléliser les accès mémoire.
|Mais ça ne garantit rien. L'écriture n'est pas forcement |faite. C'est bon pour des choses « jettables », mais je n'ai |pas le droit d'informer le client que son ordre a été pris en |compte tant que je ne peux pas garantir pouvoir le récupérer, |même en cas de crash système.
Qu'il s'agisse de memory-mapping ou d'écriture d'une séquence d'octets, là n'est pas la question. Sans flush il n'y a pas de garantie, ni dans un cas ni dans l'autre.
(Attention. Je crois que ton propos peut préter à la confusion. À ce niveau-ci, on parle plus volentiers de sync que de flush.)
Tout à fait. Sauf qu'il y a une option d'open ou de fcntl qui fait que toute écriture est synchronisée. Tandis que s'assurer la synchronisation avec mmap est plus complex. (Je parle de Unix ici, parce que je n'ai pas la moindre idée comment ça se passe sous Windows. Je suppose qu'une persistance robuste est possible sous Windows, mais je n'ai pas la moindre idée comment y arriver.)
Et c'est la synchronisation, évidemment, qui coûte les dix millisecondes.
|> > Dans les applications que j'ai vu, le goulot a prèsque |> > toujours été l'écriture disque.
Sur quoi j'ai mentionné un autre genre d'applications... la réponse pourrait presque être amusante:
|Si tu régardes autour de toi, tu verras que la plupart des |programmes font bien peu de choses, en somme.
Qui ne voit pas assez loin ?
Regarde autour de toi. Pas seulement au boulot, où tu travailles peut-être dans un domaine où la performance CPU est importante, mais plus généralement. Les ordinateurs dans ta voiture, par exemple. Les serveurs de page web (ou il y a certainement quelques un où la performance est importante, mais combien par rapport à ceux qui ne font que de resservir des pages tout faites ou gérer un chariot d'achat). Les ordinateurs de l'état (je suppose que tu paies des impots, ou que tu as un permit de conduire), les ordinateurs du boulanger (qui s'appelle pas toujours par le nom d'ordinateur), ou du grande surface.
Qu'est-ce qui définit "la plupart" ?
En effet, plusieurs définitions sont possible. Si on ne considère que le nombre d'instances des programmes qui tournent, par exemple, le fait est trivialement vrai (plus de 90% du marché des processeurs concerne les systèmes embarqués). Mais une programme qui tourne sur 10 millions d'appareils, est-ce qu'on le compte une fois, ou 10 millions ?
Si on parle de nombre de programmes différents, c'est plus difficile à chiffrer. J'avoue là que je prends un point de vue un peu « intéressé » -- je régarde les offres d'emploi et les démandes pour des programmeurs. Là, je peux dire qu'en filtrant sur C++ (et éventuellement des critères géographiques très largues), le nombre d'offres où la performance CPU du programme serait une considération est extremement faible. Mais peut-être des offres de ce genre se traitent sur un autre marché, peut-être entre-amis, et que je ne les vois pas.
|Tu fais donc beaucoup de calcul pour peu d'affichage, sur de |grands jeux de données en mémoire. Ce sont typiquement des |applications numériques où c'est le cas, ou peut-être les |jeux. Mais ce n'est pas typique de beaucoup de programmeurs ; |si je régarde dans les démandes d'emploi, par exemple, il y a |fort peu de démande pour les matheux, en dehors des banques |(et les programmes de marché sont un peu spéciaux comme |applications numériques, parce qu'ils ne traitent en général |qu'un petit jeu de données, en lui appliquant des formules on |ne peut plus compliquées).
Je suis impressionné par la portée de l'interprétation et du jugement que vous vous permettez de faire. Le "matheux qui fait beaucoup de calcul pour peu d'affichage, sans perspective professionnelle sinon dans le bancaire pour faire des trucs très compliqués avec peu de données" avait jusqu'à présent une certaine considération pour vous.
J'ai de la considération pour eux, aussi. Je crois même que ce qu'ils font est important. Mais je crois aussi qu'ils sont une faible minorité des programmeurs.
Comme j'ai dit, je ne vois pas beaucoup d'offres d'emploi dans ces domaines. Ça ne veut pas dire que ce qu'ils font est sans importance ; je soupçonne même que c'est globalement plus important que ce que font la plupart des programmes.
Mais ce n'était pas mon propos. Tout ce que j'ai dit, c'est que la plupart des programmeurs n'en sont pas directement concernés par la différence en vitesse entre un appel virtuel et un appel non-virtuel.
-- James Kanze GABI Software http://www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34