|
Publicité ' | ||||||||||||||||||||||||
|
|
#61 | |
![]() ![]() |
Citation:
Mais la conception reste, malgré tout, selon moi une nécessité absolue: Il ne s'agit, bien sur, que de mon point de vue, mais, selon moi, il est mauvais et dangereux de vouloir dissocier le processus de conception de celui de l'implémentation: ils prennent tous deux place dans un processus qui commence avec la demande d'un client "je voudrais une application qui..." et qui s'achève (plus ou moins, mais il faut encore considérer le problème de la maintenace Si tu te trouve une fois dans une situation dans laquelle il t'est impossible d'implémenter ce qui a été conçu, tu fera l'effort de t'adapter. Si tu te trouve quasiment systématiquement dans une situation dans laquelle il t'est impossible d'implémenter ce qui a été conçu, tu va très rapidement (être tenté de) décréter que "la conception ne sert à rien" ou que "c'est une perte de temps" et renoncer à y recourir... Or, ce forum et la vie de tous les jours fourmillent d'exemples qui tendent à prouver toute l'utilité de la conception et les risques encourus lorsque l'on n'y a pas apporté une "attention suffisante". LSP ne s'applique pas uniquement entre deux niveaux (entre la classe mère et son héritière directe), mais, aussi (et surtout C'est à dire que, pour le respecter, une propriété valide pour l'arrière-arrière-arrière-arrière-grand mère d'une classe doit l'être également pour son arrière-arrière-arrière-arrière-petite fille. La conséquence directe étant que, tu dois pouvoir "sans te poser de question" décider d'utiliser n'importe quelle classe "ancêtre" comme type à utiliser pour créer une collection d'objets, et que tu dois pouvoir y placer et utiliser (même si c'est en étant limité à l'interface de la classe ancêtre) ... n'importe quelle objet qui en dérive de manière directe ou indirecte. Et ce que je reproche aux langages "tout objet" (bien que je sache parfaitement faire avec), c'est que, oui, on peut dire de n'importe quoi que "c'est un objet", mais qu'il est, surtout si l'on en reste au niveau de l'étude du langage et que l'on ne peut donc, a priori, pas déterminer l'usage qui sera fait de celui-ci, impossible de déterminer un ensemble de propriétés qui, quoi qu'il arrive, quel que soit le type de l'objet créé, représentera le "plus petit ensemble" de propriétés correctes et valides du point de vue de LSP... En effet, si tout dérive de manière (très certainement) indirecte de la classe Object (quelle que soit l'orthographe choisie), tu es susceptible de placer un objet de type voiture (qui dérive de véhicule à moteur, qui dérive de véhicule, qui dérive de matière inorganique, qui dérive d'objet) et un objet de type pomme (qui dérive de fruit, qui dérive de matière organique, qui dérive d'objet) dans une même collection basée sur le type Object... Or, j'ai beau chercher, je ne vois pas d'ensemble de propriétés communes entre une pomme et une voiture... Cela n'est qu'un exemple, mais je pourrais le reproduire avec la très grosse majorité des types que l'on est susceptible de vouloir créé
__________________
en bas de page
|
|
|
|
00
|
|
|
#62 | ||
|
Membre chevronné
![]() Inscription : juin 2009 Messages : 632 ![]() |
Citation:
Citation:
Après, je ne dis pas qu'une telle hiérarchie est meilleur qu'une autre. |
||
|
00
|
|
|
#63 | ||||
|
Membre chevronné
![]() ![]() Inscription : septembre 2008 Messages : 680 ![]() |
Remarque, on peut dire la même chose de void*.
Contient-elle seulement des fonctions membres, cette classe Object ? Edit: Pour D 1.0 j'ai trouvé ça : Code :
Et pour D 2.0 : Code :
Un peu moins pire (le print() en moins), mais bon…
__________________
Cours : Initiation à CMake Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours) Ce message a été tapé avec un clavier en disposition bépo. |
||||
|
|
00
|
|
|
#64 |
|
Débutant
Inscription : mai 2006 Messages : 615 ![]() |
Le C++ ne se fera jamais remplacer. il évoluera.
|
|
|
00
|
|
|
#65 | |||
![]() ![]() |
Citation:
J'ai bien dit (c'était le sens de ma phrase) qu'une telle hiérarchie prenait, à mon sens, certaines libertés par rapport à LSP. Et, justement, je me disais que je n'étais pas vraiment allé jusqu'au bout de mon raisonnement... et tu me donne une occasion "unique" de le poursuivre Nous sommes donc d'accord sur ce qu'implique LSP, et sur le fait qu'il s'applique aux N niveaux d'héritage Or, le seul ensemble de "propriétés communes" (c'est tout le sens de LSP) que l'on puisse trouver afin de décider (en respectant LSP) de créer une classe ancêtre commune à toutes les autres est... un ensemble vide. Autrement dit, la classe Object (ou quelle que soit son orthographe) ne fournirait aucun service serait composée plus ou moins comme suit: Code :
Mais la conséquence directe, c'est que tu ne peux pas envisager d'utiliser concrètement l'instance d'une classe dérivée de Object sans... passer par un downcast... Or, c'est là que le bât blesse: si j'admet que le downcast est *parfois* intéressant / utile / nécessaire, j'estime qu'il est mauvais de forcer l'utilisateur à l'utiliser de manière systématique car, dans certains cas, cela force l'utilisateur à mettre en place, par exemple, un pattern "chaine de responsabilités", et donc à complexifier le desing de l'application bien plus que ce qu'il aurait été nécessaire si l'héritage de Object n'avait pas été effectué (forçant l'utilisateur à créer une collection d'objets pris dans le sens moins "générique"). De plus, l'héritage d'une classe commune présente un autre effet de bord, assez particulier: celui de "déporter" une série de responsabilités. Imaginons une collection d'objets. Normalement, la collection est sensée savoir quel type d'objet concrets elle doit accepter et renvoyer: La responsabilité d'accepter d'ajouter un objet à la collection sur base de la cohérence de type devrait, normalement, échoir à... la collection... De même, lorsque l'on accède à un élément de la collection, nous sommes en droit d'obtenir un objet, à tout le moins, utilisable... Or, si on crée une collection de Object, non seulement, nous disons à la collection "tu peux tout accepter, y compris de mettre une pomme à coté d'une voiture", mais, en plus, nous déportons la responsabilité de cohérence de type vers la fonction qui devra manipuler la collection... A charge de l'utilisateur de veiller à ce que les types manipulés lors de l'insertion ou de la récupération d'éléments soit cohérent. A l'insertion, nous pouvons assurer une certaine cohérence de type en décidant d'insérer non pas des instances de Object, mais plutôt des instances de VehiculeAMoteur (incluant certains bateaux, des camions, des voitures et... des trottinettes à moteurs) A l'utilisation de la collection, ou bien nous nous reposons sur le fait que l'insertion a assuré une certaine cohérence des données (... en espérant que c'est bien le cas), ou bien, nous préférons quand même vérifier que le downcast a réussi, mais, quoi qu'il en soit, nous devons downcaster l'Object récupéré en, par exemple, VehiculeAMoteur, afin de pouvoir "ratisser large" et manipuler certains bateaux, des camions, des voitures ou... des trottinettes à moteurs... Au passage, je signale qu'il y aurait sans doute également un problème de conception si, l'on décidait de manipuler une collection d'instances de type VehiculeAMoteur alors que l'on souhaite limiter le type aux seules voitures car une même cause aura les même effets: nous devrons downcaster chaque élément avant de pouvoir l'utiliser Or, justement, LSP a, entre autre, comme conséquence de s'assurer que, quel que soit le type parent que tu décidera de prendre comme base lorsque tu crée une collection, tu puisse utiliser l'interface publique de ce type pour manipuler les éléments de cette collection sans "te poser de question"... Et il faut avouer que, non seulement, il n'est pas cohérent de permettre (comme le fait la classe Object) de placer des pommes et des voitures dans une même collection, mais, en plus, que l'interface publique de la classe Object est - définitivement - trop légère pour être d'une quelconque utilité. Voilà en quoi j'estime que la philosophie du "tout objet" prend des liberté par rapport à LSP.
__________________
en bas de page
|
|||
|
|
00
|
|
|
#66 | |||||
![]() ![]() |
Citation:
Mais, si l'on ne fait que regarder l'interface de cette classe, cela signifie qu'il est possible de comparer une pomme à une voiture, et qu'il est possible d'obtenir une chaine de caractères basée sur l'objet. Je suis désolé, mais, à mon sens, il n'y a, conceptuellement parlant, aucune cohérence ni à vouloir effectuer une telle comparaison, ni à vouloir obtenir une telle chaine de caractères. Après tout, comme voulez vous convertir une pomme ou une voiture en chaine de caractères "humainement lisible" [EDIT]J'oubliais: void* n'est pas une classe... c'est un objet de type pointeur dont le type est indéterminé... Et je suis également contre toute utilisation de ce type de pointeur
__________________
en bas de page
|
|||||
|
|
00
|
|
|
#67 | |
|
Membre chevronné
![]() Inscription : juin 2009 Messages : 632 ![]() |
Citation:
Ma question initiale dans ce post était candide, et ne se focalisait pas uniquement sur le c++. Alors sinon, oui je suis d'accord avec toi pour le reste de ton argumentation -dans le cadre du c++. Par rapport à D et le membre int opCmp(Object o) de la classe Object, j'ai envie de dire: pourquoi pas! Il faudra juste s'assurer qu'un type dérivé de Objet (sur N niveaux) ne brise pas le LSP pour ce membre et ses siblings. |
|
|
00
|
|
|
#68 | |
![]() ![]() |
Tu aurais au moins pu repsecter mon post, et prendre le paragraphe suivant, qui est à mon sens bien plus important
Citation:
La seule présence de ce downcast montre, pour "naturel" qu'il puisse sembler, à l'évidence, d'autant plus qu'il est systématique, que les concepteurs de java ont "fait fausse route" en décidant de présenter une collection permettant de maintenir ensemble des instances dérivées de Object... De même, la fonction toString a pour comportement par défaut de fournir une chaine contenant... l'adresse de l'objet... C'est, quelque part, normal dans le sens où, autrement, l'utilisateur aurait été tenu de redéfinir cette fonction y compris pour les types pour lesquels une telle fonction est inutile / inopportune, mais elle montre clairement que, effectivement, LSP n'est pas respecté en profondeur car on ne peut pas dire que la propriété toString de la classe Object (dont on peut, soit dit en passant déjà se poser la question de la validité pour la classe Object) soit, effectivement, valide pour les classes qui en dérivent... Maintenant, il ne faut pas croire que je ne vise ici que java: je vise, de manière générale, tous les langages utilisant un principe similaire et, au delà, toute conception qui tendrait à mettre un tel principe en oeuvre
__________________
en bas de page
|
|
|
|
00
|
|
|
#69 | ||
|
Membre chevronné
![]() ![]() Inscription : septembre 2008 Messages : 680 ![]() |
Citation:
Citation:
Je n'ai personnellement jamais eu à me servir de ça, mais le fait qu'une telle chose existe dans Boost est bien la preuve qu'un tel besoin existe. Et sa légitimité est enforcée par les quelques gourous qui peuplent le comité de validation ! De ce point de vue, Object serait un Boost.Any natif. Pour le reste nous sommes d'accord, rien ne justifie selon moi qu'Object possède la moindre fonction membre…
__________________
Cours : Initiation à CMake Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours) Ce message a été tapé avec un clavier en disposition bépo. |
||
|
|
00
|
|
|
#70 | |
![]() ![]() |
Citation:
En ce sens, avoir la possibilité de disposer tantôt d'une chaine de caractères, tantôt d'un entier ou d'un double, à l'instar de ce que fait boost.any est louable. Mais il reste de la marge entre cette optique adaptée à certaines situations particulières (même si elles sont, en définitive, assez communes) et l'optique qui consiste à estimer que, quel que soit le type manipulé, il puisse être considéré comme compatible avec n'importe quel autre. Or, c'est justement l'optique suivie, en définitive, par les langages qui placent, d'une manière ou d'une autre, une classe Object en haut de la hiérarchie d'héritage. Autrement dit: permettre une telle substituabilité dans des cas bien déterminés, oui, généraliser cette substituabilité quelles que soient les circonstances, non
__________________
en bas de page
|
|
|
|
00
|
|
|
#71 |
|
Membre éclairé
![]() Inscription : juillet 2008 Messages : 339 ![]() |
Bonjour, j'utilise le D depuis maintenant 2 ans.
Je m'en sers pour mes projets amateurs et quand j'ai besoin de petits outils/scripts au boulot (surtout traiter des gros fichiers binaires, là où Perl n'est pas très pratique). Je trouve qu'il règle quelques problèmes de C++ génants: - vitesse de compilation - fonction imbriquées manquantes - templates durs à écrire et à comprendre - niveau très hétérogène du code C++ en circulation - pas de propriétés - pléthore de smart pointers et classes String différents... Il y a un autre problème qui m'énerve particulièrement avec C++: la quantité de chose à faire pour refactorer quelque chose pousse (inconsciemment ?) à ne pas refactorer, pour aller plus vite. Dans D les fonctions imbriquées, la disparition des headers et la compilation plus rapide apporte quelque chose de mieux à mon avis. J'ai aussi constaté que j'étais beaucoup plus productif en D qu'en C++ à cause de tout ces facteurs cumulés. Par contre, D vient avec un lot de problèmes assez importants, surtout du côté de l'environnement, qui ont été assez bien résumés ici et là. Je rajouterais aussi qu'il n'est pas si facile d'apprendre le D, le langage est assez mouvant et la barrière à l'entrée peut en rebuter beaucoup. Il n'est pas rare de devoir écrire un binding car il n'existe pas... Quand au problème de la classe mère Object, je pense que c'est un faux problème. Comme le C#, D fait la séparation entre les "struct" qui sont analogues aux structures C (rien de caché) et les "class" qui contiennent d'office un pointeur vers la TMV et un intrinsic_ptr. On donc est pas obligé de payer pour quelque chose qu'on utilise pas. En résumé: D me semble indiqué pour des projets amateurs, pas pour des projets professionnels pour le moment. Sous-forum sur D: http://www.developpez.net/forums/f11...es-langages/d/ |
|
00
|
|
|
#72 | ||
|
Membre éprouvé
![]() Inscription : mai 2005 Messages : 228 ![]() |
Je connais pas boost.Any mais en D2, l'équivalent, ça serait pas plutôt le type Variant ?
http://www.digitalmars.com/d/2.0/pho...d_variant.html @Koala : Ce que tu dis sur les collections d'objets se tient pour des langages comme Objective-C ou Java, mais je te rappellerai juste que D est un langage multiparadigme, tout comme le C++. Tu n'es absolument pas obligé de faire de l'objet en D, et les collections à base de templates existent aussi en D. Tu n'as donc pas besoin de downcaster et le compilateur est tout à fait en mesure de vérifier que tu ne mélanges pas les pommes et les voitures. Code :
|
||
|
|
00
|
|
|
#73 | |
|
Membre chevronné
![]() ![]() Inscription : septembre 2008 Messages : 680 ![]() |
Citation:
__________________
Cours : Initiation à CMake Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours) Ce message a été tapé avec un clavier en disposition bépo. |
|
|
|
00
|
|
|
#74 |
|
Membre éprouvé
![]() Inscription : mai 2005 Messages : 228 ![]() |
|
|
|
00
|
|
|
#75 | |||
|
Expert Confirmé Sénior
![]() ![]() Emmanuel DelogetDéveloppeur informatique Inscription : septembre 2007 Messages : 1 828 ![]() |
Citation:
Faux débat. Les fonctions imbriquées ne sont utiles que si on a pas la possibilité d'écrire des fonctions anonymes (ce qui vient dans le futur standard). Dans le standard courant, il est tout à fait possible de créer une classe dans une fonction, et donc de créer autant de fonction imbriquées qu'on le souhaite - je reconnait toutefois que c'est tiré par les cheveux. Code :
Ah si. En même temps, les template sont plus destinés aux créateurs de librairies qu'aux développeurs d'applications. Mais je le concède, ils peuvent être complexe à comprendre. C'est vrai dès que tu as du code en liberté. Le C++ n'est ni plus ni moins touché que les autres langages. Qui n'ont de toute façon strictement aucune raison d'être dans le cadre d'une architecture orientée objet, donc ça n'est pas catastrophique. La classe std::basic_string est standardisée - c'est donc la seule à utilisée, à moins d'une contre-indication liée à un framework quelconque (les coupables : Qt, MFC, ... principalement pour des raisons historiques, ces framework datant souvent d'une époque ou les compilateurs ne respectait pas le standard de 98). Les classes du TR1 (héritée de boost) présentent les smart pointer qu'il faut. Elles ont été intégrée au futur standard C++ - donc elles sont normalisées aussi. Je ne vais pas dire que le C++ n'a pas, en tant que langage, des problèmes importants (parce que dieu sait qu'il en a). Certains des points que tu soulèves ont leur importance, par contre, d'autre sont quand même des faux problèmes.
__________________
[FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...] Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi. Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça. Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas. Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas. |
|||
|
00
|
|
|
#76 |
|
Débutant
Inscription : mai 2006 Messages : 615 ![]() |
+1 pour l'ensemble des faux problèmes mis en exergue
|
|
|
00
|
|
|
#77 |
|
Membre Expert
![]() Inscription : juillet 2006 Messages : 1 522 ![]() |
Je n'aurais pas mis la plupart des problèmes la, mais pour la métaprog, c'est vraiment être de mauvaise foie que de ne pas vouloir voir le problème en C++.
Oui, on peut en faire, oui on peut en faire des trucs sympa, mais c'est absolument mal pensé et relativement difficile à mettre en œuvre. Rien que les static if, les CTFE ou les mixins, ou simplement de pouvoir templater sur n'importe quoi (string, float, etc . . .) c'est simplement des fonctionnalités de base qu'on aimerait bien retrouver en C++. Par exemple, impossible d'implémenter de façon simple des fonction swizzle en C++ sur des vecteurs. Pour idée, voila ce qu'on fait en D : http://h3.team0xf.com/ctrace/ http://www.99-bottles-of-beer.net/language-d-1212.html http://www.dsource.org/projects/ddl/...k/meta/regex.d |
|
|
00
|
|
|
#78 | |
|
Expert Confirmé
![]() ![]() Joel LamotteDéveloppeur de jeux vidéo Inscription : août 2004 Messages : 1 627 ![]() |
Citation:
|
|
|
00
|
|
|
#79 | |||||
![]() ![]() |
Citation:
L'héritage (publique), quel que soit le niveau envisagé permet de faire passer une instance d'une classe dérivée pour une instance de l'une de ses classes mère /ancêtre... A ce titre, je salue la fait que D permette de préciser un type d'objet à placer dans une collection (list par exemple) et qu'il fournisse le moyen de vérifier que les objets que l'on tente d'y placer correspondent. Par contre, à moins qu'il n'y ait un mécanisme qui soit en mesure d'empêcher la création de collection... d'Objects, rien n'empêchera l'utilisateur d'écrire un code proche de Code :
Mais, encore une fois, je fais ce reproche de manière tout à fait générale, et je l'adresse aussi (principalement
__________________
en bas de page
|
|||||
|
|
00
|
|
|
#80 | |||
|
Membre chevronné
![]() Inscription : juin 2009 Messages : 632 ![]() |
Citation:
Après que cela entraine de gros problèmes de conception -par méconnaissance-, j'ai envie de dire, ce n'est pas mon affaire Conceptuellement, ça tient la route. C'est l'essentiel, non ? |
|||
|
00
|
Copyright © 2000-2013 - www.developpez.com