IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?


Sujet :

Langage C++

  1. #61
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?

    Le problème c'est que deux principes quelque peu différents ont été présentés ici:

    "If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T"
    -- BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988)
    "Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T"
    -- Liskov and Jeannette Wing, 1994 paper
    La première version caractérise une relation de sous typage alors que la seconde pose cette relation comme condition préalable.

    La seconde formulation est la plus pertinente puisqu'on s'interesse au changement de visibilité de fonction virtuelle (la relation de sous typage est acquise).
    C'est pourquoi il me parait absurde de considérer une substitution de type non polymorphique. Pour reprendre les termes de gl, on est dans un cadre de l'usage polymorphique uniquement (on fixe le type statique à A et on fait varier le type dynamique de A à B).

    Alors est-ce que le changement de visibilité d'une fonction virtuelle est une condition suffisante pour violer LSP?

    Je dirai: Non.
    Ca me parait évident.

    Le code d'exemple proposé par Flob90 ( http://www.developpez.net/forums/d95...p/#post5372628 ) montre clairement que la condition n'est pas suffisante.

    Cependant, on ne peut pas dire que jamais un changement de visibilité n'infirmera LSP.
    On ne peut pas dire grand chose, si ce n'est répondre à la question

  2. #62
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?

    Le problème c'est que deux principes quelque peu différents ont été présentés ici:





    La première version caractérise une relation de sous typage alors que la seconde pose cette relation comme condition préalable.
    "If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T"
    -- BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988)
    La seconde formulation est la plus pertinente puisqu'on s'interesse au changement de visibilité de fonction virtuelle (la relation de sous typage est acquise).
    "Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T"-- Liskov and Jeannette Wing, 1994 paper
    Pour moi, la relation de sous typage n'est acquise que... si on peut effectivement vérifier le principe.

    Autrement, tu en viendrait à accepter de créer un sous type "voiture" héritant d'un type "animal" parce que, à l'utilisation, tu veux appeler la fonction "manger", et qu'elle se trouve dans l'interface d'animal et "tant pis si une voiture ne mange pas"...
    C'est pourquoi il me parait absurde de considérer une substitution de type non polymorphique. Pour reprendre les termes de gl, on est dans un cadre de l'usage polymorphique uniquement (on fixe le type statique à A et on fait varier le type dynamique de A à B).

    Alors est-ce que le changement de visibilité d'une fonction virtuelle est une condition suffisante pour violer LSP?

    Je dirai: Non.
    Ca me parait évident.
    Pourquoi cela te parait-il évident pour moi, c'est justement le contraire

    Si l'on prend la version de 1988, le comportement de l'objet hérité est modifié (un appel est accepté pour le type de base alors que le type dérivé aurait refusé l'appel)

    Si on prend la version de 1994, je crois qu'il faut commencer par se mettre d'accord sur ce qu'est une propriété prouvable pour un objet (a property provable about objects).

    Pour ma part, je considère comme propriété prouvable" la capacité que l'on a à appeler n'importe quelle fonction de l'interface publique.

    Or, pour un type hérité redéfinissant une des fonctions de l'interface publique du type de base en y ajoutant des restrictions d'accès, la capacité que l'on a d'appeler cette fonction pour le type dérivé est annulée par cette décision, et la propriété n'est donc plus prouvable / valide.

    Bref, que l'on prenne n'importe quelle version de son principe, on en revient au même: tout nous incite à refuser un héritage pour lequel nous apposons des restrictions d'accès à une fonction se trouvant dans l'interface publique du type de base.

    Si tu prend la décision d'utiliser l'héritage public malgré tout, alors que Liskov t'incite à ne pas le faire, tu te prépares des soucis sans noms pour la suite.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #63
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Pour ma part, je considère comme propriété prouvable" la capacité que l'on a à appeler n'importe quelle fonction de l'interface publique.
    Oui.

    Citation Envoyé par koala01 Voir le message
    Or, pour un type hérité redéfinissant une des fonctions de l'interface publique du type de base en y ajoutant des restrictions d'accès, la capacité que l'on a d'appeler cette fonction pour le type dérivé est annulée par cette décision, et la propriété n'est donc plus prouvable / valide.
    Cette affirmation est fausse car il existe un contre exemple qui l'invalide.

    Ce contre exemple fut introduit par Flob90.
    http://www.developpez.net/forums/d95...p/#post5372628

    A partir de là, je ne peux que répondre par la négative à la question initiale.
    Je ne porte pas de jugement de valeur quant à la pertinence d'une telle construction dans un programme.

    Citation Envoyé par koala01 Voir le message
    Si tu prend la décision d'utiliser l'héritage public malgré tout, alors que Liskov t'incite à ne pas le faire, tu te prépares des soucis sans noms pour la suite.
    Point de substitution de type sans héritage publique. Les autres formes d'héritages sont hors sujets.

  4. #64
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Point de substitution de type sans héritage publique. Les autres formes d'héritages sont hors sujets.
    Pas tout à fait vraie mais en effet hors sujet (cf LSP réduit via un héritage privé/protégé sur GotW)

    Citation:Envoyé par koala01
    Or, pour un type hérité redéfinissant une des fonctions de l'interface publique du type de base en y ajoutant des restrictions d'accès, la capacité que l'on a d'appeler cette fonction pour le type dérivé est annulée par cette décision, et la propriété n'est donc plus prouvable / valide.

    Cette affirmation est fausse car il existe un contre exemple qui l'invalide.

    Ce contre exemple fut introduit par Flob90.
    J'ai en effet introduit cette exemple avant de conprendre qu'il ne prouve rien car découle du fonctionnement du langage et la décision que la relation IS-A est justifié, chose qui ne l'est pas si l'on effectue une analyse préalable. (cf tout les post de koala sur la conception).

    (on fixe le type statique à A et on fait varier le type dynamique de A à B)
    AMA il n'y a qu'un seul type à considérer, le dynaminque, et aucune raison de prendre en compte le type statique pour déterminer ce qui est ou non prouvable (dans notre cas l'appartenance à l'interface). Je ne crois pas que ces différences de type et de comportement du langage à leur égare ai une influence sur la phase de conception et donc la vérification du LSP.

  5. #65
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Oui.


    Cette affirmation est fausse car il existe un contre exemple qui l'invalide.

    Ce contre exemple fut introduit par Flob90.
    http://www.developpez.net/forums/d95...p/#post5372628
    Le fait est que le contre exemple de flob ne prouve rien, car il est dans les attributions d'aucun langage quel qu'il soit de vérifier s'il est effectivement opportun de recourir à l'héritage.

    Le langage se "contente" donc d'appliquer les règles aberrantes occasionnées par ta propre décision inopportune.

    Comme il n'a aucun moyen de tester le type réel sur lequel s'effectue une action polymorphe, le langage n'a pas d'autre choix que d'estimer que la décision de faire hériter une classe d'une autre est cohérente et opportune (en vertu de LSP).

    Il estime donc que toute propriété valide pour la classe de base l'est également pour la classe dérivée, en ce, y compris... la fameuse propriété invalidée par l'ajout de restriction à l'accessibilité.

    Or, d'un point de vue conceptuel, si tu admet qu'une propriété est la capacité d'appeler n'importe quelle fonction de l'interface publique, tu ne peux pas faire autrement que d'admettre que si, pour une classe dérivée, une fonction passe de l'accessibilité publique à une accessibilité plus restrictive (protected ou private), on ne dispose plus, pour la classe dérivée (oserais-je dire "sans aller voir ce qu'il en est dans la classe de base ) de la capacité d'appeler la fonction en question.

    A partir de là, tu ne peux pas faire autrement que d'admettre qu'une propriété valide pour la classe de base est rendue invalide pour la classe dérivée.

    Et, à partir de là, il ne te reste plus qu'une seule conclusion à tirer: l'héritage n'est pas opportun en l'état.

    J'ai déjà cité les possibilités qui s'offrent à toi à partir de cette conclusion, je ne vais donc pas les répéter
    A partir de là, je ne peux que répondre par la négative à la question initiale.
    Je ne porte pas de jugement de valeur quant à la pertinence d'une telle construction dans un programme.
    Le problème est que, justement, une telle construction dans un programme n'a aucune valeur positive et est, justement, à rejeter d'un point de vue conceptuel.

    Et, fatalement, si une telle construction devrait être rejetée à la conception, tu ne devrais purement et simplement jamais la rencontrer dans l'implémentation.

    Autrement, cela va passer à la compilation et tu félicitera l'utilisateur d'avoir assez bête pour perdre le type réel d'un objet de type dérivé en permettant d'appeler (depuis l'extérieur) une fonction... qu'il n'aurait jamais du pouvoir appeler s'il s'en était tenu au type réel.
    Point de substitution de type sans héritage publique. Les autres formes d'héritages sont hors sujets.
    Nous sommes bien d'accord là dessus, mais il est bon de rappeler de temps en temps que l'on parle bel et bien d'héritage public
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #66
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Le fait est que le contre exemple de flob ne prouve rien, car il est dans les attributions d'aucun langage quel qu'il soit de vérifier s'il est effectivement opportun de recourir à l'héritage.

    Le langage se "contente" donc d'appliquer les règles aberrantes occasionnées par ta propre décision inopportune.
    Les règles aberrantes, qui sont celles du C++, s'appliquent bien évidement au contre exemple.

    Il [le langage] estime donc que toute propriété valide pour la classe de base l'est également pour la classe dérivée, en ce, y compris... la fameuse propriété invalidée par l'ajout de restriction à l'accessibilité.
    L'estimation se fait par rapport à l'interface de base. Ce qui parait tout à fait normal puisque nous sommes dans un cas de substitution de type.

    Or, d'un point de vue conceptuel, si tu admet qu'une propriété est la capacité d'appeler n'importe quelle fonction de l'interface publique, tu ne peux pas faire autrement que d'admettre que si, pour une classe dérivée, une fonction passe de l'accessibilité publique à une accessibilité plus restrictive (protected ou private), on ne dispose plus, pour la classe dérivée (oserais-je dire "sans aller voir ce qu'il en est dans la classe de base ) de la capacité d'appeler la fonction en question.

    A partir de là, tu ne peux pas faire autrement que d'admettre qu'une propriété valide pour la classe de base est rendue invalide pour la classe dérivée.
    La propriété est toujours accessible lorsque nous y accédons au travers de l'interface de base via une référence ou un pointer sur le type de base. Ce contexte particulier est directement corrélé à la problématique: c'est la traduction en C++ d'une substitution de type.

    Je ne décrète pas ça gratuitement. C'est vérifié avec un programme dont le behavior est inchangé lorsqu'on opère la substitution.

    Et, à partir de là, il ne te reste plus qu'une seule conclusion à tirer: l'héritage n'est pas opportun en l'état.
    La conclusion que je tire à partir de là est la réponse à la question posée:

    Non, tout changement de visibilité d'une fonction virtuelle n'implique pas forcément un viol du LSP.

    Le problème est que, justement, une telle construction dans un programme n'a aucune valeur positive et est, justement, à rejeter d'un point de vue conceptuel.

    Et, fatalement, si une telle construction devrait être rejetée à la conception, tu ne devrais purement et simplement jamais la rencontrer dans l'implémentation.
    C'est aussi mon sentiment: une telle construction révèle un sérieux problème de conception. Cependant, JolyLoic a esquissé un usage qui me parait sensé:

    privée hors virtualité signifie : "à usage interne"
    privée plus virtualité signifie : "à l'usage des classes de base"

  7. #67
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Les règles aberrantes, qui sont celles du C++, s'appliquent bien évidement au contre exemple.
    Ce ne sont pas les règles de C++ ni de java ou de n'importe quel autre langage...

    Ce sont des règles aberrantes qui découlent exclusivement d'une décision inopportune / inadaptée de ta part.

    Et, comme le langage (quel qu'il soit) n'est absolument pas armé pour vérifier l'opportunité de tes décisions, il les applique en "brave petit soldat", sans se poser de question.

    Comme tu as décidé que la classe dérivée héritait de la classe de base alors qu'elle n'aurait jamais du le faire (*) , le langage n'a d'autre choix que d'appliquer la seule règle qu'il connaisse en matière d'héritage public: tout ce qui fait partie de l'interface publique de la classe de base se retrouve dans l'interface publique de la classe dérivée.

    (*) Si je dis que tu n'aurais jamais du le faire, c'est :
    1- parce que, si tu as décidé de déclarer dans l'accessibilité privée ou protégée de ta classe dérivée la fonction redéfinie, c'est que tu ne voulais pas que l'on puisse y accéder depuis l'extérieur... Sinon, tu l'aurais laissée dans l'accessibilité publique
    2- parce que, du fait de ce changement d'accessibilité, il y a bel et bien une propriété valide dans la classe de base qui est invalide dans la classe dérivée (LSP inside )
    L'estimation se fait par rapport à l'interface de base. Ce qui parait tout à fait normal puisque nous sommes dans un cas de substitution de type.
    Le problème, c'est que l'interface (publique) de la classe de base ne correspond pas à ce que propose l'interface de la classe dérivée.
    La propriété est toujours accessible lorsque nous y accédons au travers de l'interface de base via une référence ou un pointer sur le type de base. Ce contexte particulier est directement corrélé à la problématique: c'est la traduction en C++ d'une substitution de type.
    C'est parce que tout langage OO va appliquer la même règle sans se poser de question: en cas d'héritage publique, toute l'interface de la classe de base se retrouve dans l'interface des classes dérivées.

    Le problème, c'est que cela va en contradiction avec tes propres décisions

    Alors, effectivement, si tu prend une mauvaise décision, tous les langages réagiront de la même manière en te permettant d'appeler la fonction "depuis l'extérieur" dés le moment où tu travaille avec une référence ou un pointeur vers le type de base...

    Mais, si tu as décidé de faire passer la fonction dans l'accessibilité protégée ou privée dans la classe dérivée, c'est, justement, parce que tu ne voulais pas que l'on puisse y accéder depuis l'extérieur.

    Dés lors, il est purement et simplement illogique d'accepter que l'on accepte de le faire au travers de la classe de bas, et c'est ta décision inappropriée d'utiliser l'héritage qui te permet ce comportement illogique.
    Je ne décrète pas ça gratuitement. C'est vérifié avec un programme dont le behavior est inchangé lorsqu'on opère la substitution.
    C'est comme si tu disais qu'un pointeur est codé sur un unsigned long parce que c'est ce que t'indique le compilateur.

    Personnellement, je pourrais alors te soutenir, travaillant avec un OS 64bits et un compilateur fournissant des exécutables 64bits, qu'un pointeur est codé sur un unsigned long long, parce que c'est bel et bien ce que m'indique le compilateur (il me lance d'ailleurs un avertissement lorsque j'essaye un cast C style d'un pointeur vers un unsigned long).

    Seulement, au niveau de l'héritage, le compilateur ne fait... qu'appliquer tes règles, sans se poser de question, en brave petit soldat.

    A partir du moment où tu décides de faire hériter la classe B de la classe A, le compilateur n'a pas le choix: il doit accepter gérer n'importe quel objet de type B comme s'il s'agissait d'un objet de type A lorsque l'on appelle une fonction prenant une référence ou un pointeur sur une instance de type A...

    Y compris si cela n'a absolument aucun sens réel...

    Et donc, cela revient à accepter qu'il fasse passer un objet de type Voiture pour un objet de type Animal, simplement parce que tu as décidé de faire hériter la classe Voiture de la classe Animal, alors que cela n'a strictement aucun sens
    La conclusion que je tire à partir de là est la réponse à la question posée:

    Non, tout changement de visibilité d'une fonction virtuelle n'implique pas forcément un viol du LSP.
    Le problème, c'est que tu ne peux pas te baser sur le comportement du compilateur pour cela...

    LSP est, je le redis une fois de plus, un "GO - NO GO" de conception qui doit te permettre de décider en connaissance de cause d'utiliser l'héritage publique.

    Si tu décide de l'utiliser alors que tu ne devrais pas (par exemple en faisant hériter ta classe Voiture de la classe Animal), tu ne peux pas compter sur le langage pour te signaler que tu fais une boulette parce qu'il n'a aucun moyen de le remarquer et qu'il appliquera donc l'héritage "à la lettre" que ce soit une "bonne idée" ou non.

    A partir du moment où la décision est prise, le langage agira en conséquence, aussi illogique cela puisse-t-il être au niveau de l'exécution, et tu pourra appeler la fonction "manger", "dormir" ou "se reproduire" depuis un objet de type Voiture (ou une fonction publique dans la classe de base alors que c'est une fonction protégée dans la classe dérivée).

    C'est aussi mon sentiment: une telle construction révèle un sérieux problème de conception.
    Oui, c'est un sérieux problème de conception... Et LSP en est la principale raison
    Cependant, JolyLoic a esquissé un usage qui me parait sensé:

    privée hors virtualité signifie : "à usage interne"
    privée plus virtualité signifie : "à l'usage des classes de base"
    Je dirais plutôt:
    privée plus virtualité signifie "à l'usage des fonctions de la classe de base".

    Tu me diras peut être "bah, ce ne sont que trois mots sans importance"... Et pourtant...

    Quand tu fais passer une fonction de l'interface publique de la classe de base vers une accessibilité restreinte (on peut parler des accessibilités protégées et privées en même temps), ce n'est pas une fonction de la classe de base (ou des classes dérivées) qui peut y accéder: c'est... n'importe quelle fonction qui utilise une référence ou un pointeur vers une instance de la classe de base.

    Autrement dit, cette fonction "à accès normalement restreint", car, même s'il s'agit de permettre l'appel depuis n'importe quelle fonction de la classe de base ou des classes dérivées, il s'agit bel et bien d'un accès restreint devient "parce qu'on est assez bête pour perdre le type réel de l'objet" et "suite à l'impossibilité du langage de se rendre compte que nous avons fait une erreur" accessible... depuis strictement partout, ou, si tu préfère : sans aucune restriction.

    Et ca, d'un point de vue conceptuel, c'est purement et simplement aberrant, anormal, et ca ouvre la porte à une série de problèmes sans noms.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #68
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Je viens de me dire qu'il serait peut être bon que je précise quelque chose au niveau des fonctions virtuelles et protégées ou privées:

    J'accepte sans aucun problème que l'on dise qu'une fonction privée et virtuelle est une fonction à l'usage des fonctions de la classe de base, car c'est le cas.

    De même, j'accepte sans aucun problème que l'on me dise qu'une fonction protégée (qu'elle soit virtuelle ou non) est une fonction à l'usage des fonctions de la classe de base ou des classes qui en dérivent, car c'est aussi le cas, qu'il y ait ou non adaptation du comportement si la fonction est virtuelle.

    Par contre, qu'il s'agisse de l'un ou de l'autre, il y a toujours une restriction sur l'usage que l'on peut faire de ces fonctions: il faut toujours passer par une fonction membre de la classe de base ou des classes dérivées.

    Comme je l'ai déjà fait savoir, j'accepterais assez facilement que l'on décide de faire passer une fonction privée ou protégée dans l'accessibilité publique d'une classe dérivée, bien qu'il faille me donner des arguments cohérents pour le faire.

    Mais le fait est que, lorsque l'on redéfini une fonction virtuelle publique de la classe de base dans une accessibilité moindre, ce ne sont pas seulement les fonction membres de la classe dans laquelle la fonction est redéfinie, ni les fonctions membres des classes qui dérivent de celle là qui peuvent y accéder, mais c'est n'importe quelle fonction, qu'elle soit libre ou membre d'une classe qui n'a strictement rien à voir avec la hiérarchie de classes qui peut accéder à la fonction redéfinie pour autant qu'elle manipule... un pointeur ou une référence vers la classe de base sans même avoir une relation d'amitié.

    On croit donc imposer une restriction à l'utilisation de la fonction alors qu'il n'y en a finalement aucune, vu que l'on est récompensé d'avoir... été assez bête pour perdre le type réel de l'objet par le fait de pouvoir accéder à cette fonction "à accès restreint" (ou du moins sensée l'être)...
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #69
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Ta longue dissertation, qui a du sens, ne change rien en ce qui me concerne. Mon avis est basé sur des faits reproductibles.

    Initialement, et spontanément (je ne suis pas un expert du C++), j'aurai répondu oui à la question posée dans cette thread: le changement de visibilité viole le LSP.
    Il y a des langages de programmation qui interdisent un tel changement de visibilité. Dans pareil cas, le LSP serait brisé dès la "compilation" et la réponse à la question serait donc immédiate.

    Je suis parfaitement conscient qu'une visibilité plus restreinte dans les classes dérivées est plus que suspecte et que cela reflète à coup sûr un sérieux problème de conception.

    Une mauvaise conception n'implique pas nécessairement une violation du LSP

    Mettre les fonctions virtuelles en accès restreint (en commençant par la classe de base) est conseillé. Il s'agit, après vérification, de l'idiom NVI - Non-Virtual Interface.

  10. #70
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Ta longue dissertation, qui a du sens, ne change rien en ce qui me concerne. Mon avis est basé sur des faits reproductibles.
    Reproductibles, oui, mais basés sur des erreurs de conception...
    Initialement, et spontanément (je ne suis pas un expert du C++), j'aurai répondu oui à la question posée dans cette thread: le changement de visibilité viole le LSP.
    ET c'est bel et bien le cas... LSP est un principe de conception, qui doit donc rester "aussi indépendant que possible" du langage dans lequel ce qui a été conçu sera implémenté
    Il y a des langages de programmation qui interdisent un tel changement de visibilité. Dans pareil cas, le LSP serait brisé dès la "compilation" et la réponse à la question serait donc immédiate.
    Si ce n'est qu'aucun langage ne pourra te garantir que le changement de visibilité sera effectivement opportun, pas plus qu'il ne pourra te garantir que la décision de faire hériter la classe Voiture de la classe Animal sera une décision opportune.
    Je suis parfaitement conscient qu'une visibilité plus restreinte dans les classes dérivées est plus que suspecte et que cela reflète à coup sûr un sérieux problème de conception.
    Exactement, et c'est bel et bien LSP qui est mis en oeuvre, et qui peut te permettre d'éviter ce problème.

    Encore faut il accepter l'idée de l'appliquer "à la lettre".
    Une mauvaise conception n'implique pas nécessairement une violation du LSP
    Tout à fait d'accord... Mais je n'ai jamais dit non plus que toutes les erreurs de conception étaient liées à un viol de LSP...

    Je dis juste que, pour ce qui nous intéresse maintenant, l'erreur est effectivement due au non respect de LSP.
    Si ce n'est que, dans le cas présent, c'est bel et bien ce qui arrive
    Mettre les fonctions virtuelles en accès restreint (en commençant par la classe de base) est conseillé. Il s'agit, après vérification, de l'idiom NVI - Non-Virtual Interface.
    Certains semblaient dire que NVI violait LSP, et j'ai démontré plus haut que ce n'était pas le cas.

    La restriction des fonctions dans la classe de base, quitte à lever ces restrictions dans les classes dérivées, permet, effectivement, de se donner une occasion supplémentaire de respecter LSP en gardant une interface publique "aussi minimaliste que possible", et c'est bien pour cela que je peux admettre l'éventualité de faire remonter les fonctions dans une accessibilité moins restrictive dans les classes dérivées.

    Par contre, lorsqu'il est question d'ajouter des restrictions à l'acces de fonctions qui sont publiques dans la classe de base, le fait que la (les) fonction(s) visée(s) ne soient plus accessibles publiquement dans la classe dérivée (conceptuellement parlant, quoi que puisse te faire croire le compilateur) invalide l'une des propriétés de la classe de base, et l'on se trouve donc bel et bien dans le cas où... LSP est violé.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #71
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par koala01 Voir le message
    ET c'est bel et bien le cas... LSP est un principe de conception, qui doit donc rester "aussi indépendant que possible" du langage dans lequel ce qui a été conçu sera implémenté.
    Ca m'ennuie que tu continues d'affirmer ça sans avoir répondu aux différentes problématiques que j'ai évoquées concernant cette approche :
    - influence de la phase où sont faites certaines vérifications (par exemple, le fait que private soit résolu à la compilation et pas à l'exécution est de prime importance ici)
    - influence du multiple-dispatch sur la covariance des paramètres
    - ...

    LSP est un principe qui ne saurait être appliqué hors contexte, car le contexte apporte des contraintes et des garanties différentes, qui font que son application sera différente.

    Prend le problème à l'envers, essaie de raisonner par l'absurde. Considère que tu VEUX changer la visibilité de la méthode foo dans B par rapport à A (je ne sais pas pourquoi tu veux faire une chose pareille, c'est sûrement une erreur de conception, mais pourquoi pas ). L'application du LSP va te dire que pour toute fonction faisant appel à foo() avec un A, il faut que ça continue de fonctionner si on passe un B à la place du A. Ca tombe plutôt bien, c'est bien le cas en C++...

    Pour en revenir à ton exemple, je n'ai pas de blocage à faire dériver voiture de animal si, dans mon contexte, cela a du sens (j'ai dû mal à trouver un tel contexte, cela dit).

  12. #72
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Ca m'ennuie que tu continues d'affirmer ça sans avoir répondu aux différentes problématiques que j'ai évoquées concernant cette approche :
    - influence de la phase où sont faites certaines vérifications (par exemple, le fait que private soit résolu à la compilation et pas à l'exécution est de prime importance ici)
    Où est le problème Tu n'as pas à t'inquiéter de cela quand tu prend la décision de faire hériter une classe d'une autre, vu que cette décision doit être prise en phase de conception, et donc bien avant d'écrire la première lettre de la première définition de l'une des classes que tu envisage de faire intervenir dans une hiérarchie commune
    - influence du multiple-dispatch sur la covariance des paramètres
    Autant le dire, je ne considère pas que la covariance viole LSP, pour une raison bien simple:

    LSP admet parfaitement que le comportement d'une fonction soit adapté en fonction des besoins (c'est le point qui permet le fonctionnement polymorphe de l'héritage)

    Il n'y a, a priori, aucune restriction quant à l'adaptation que l'on peut observer, c'est à dire que, pour autant que l'on soit dans un contexte dans lequel l'appel d'une fonction est sensé renvoyer un résultat cohérent (que la propriété est valide) et que le résultat est, effectivement cohérent avec le contexte, la fonction peut renvoyer une valeur différente, et donc, pourquoi pas, un type différent sous certaines réserves (entre autres celle que les différents types renvoyés interviennent dans une hiérarchie de classe commune):

    Quand tu y réfléchis bien: tu as une propriété valide dans la classe de base qui est la capacité à appeler la fonction machinChose depuis l'extérieur de la classe.

    Cette propriété est également valide dans la classe dérivée, parce que, sous réserve de ne pas en changer l'accessibilité, tu dispose également de la capacité d'appeler cette fonction depuis l'extérieur de la classe pour les classes dérivée.

    Le comportement de machinChose s'adpate simplement en fonction du type réel de l'objet manipulé.

    La référence ou le pointeur sur l'objet renvoyé par la "version" de machinChose utilisée pour la classe dérivée peut parfaitement se faire passer pour un pointeur ou une référence sur l'ojbet que la version de machinChose telle que décrite dans la classe de base est sensée renvoyer, parce qu'il y a une relation d'héritage publique, fusse-t-elle indirecte (la classe qui hérite de la classe qui hérite de la classe de base)

    Si LSP a été respecté lorsqu'il a été question de créer la hiérarchie de classes pour le type de retour, et qu'il est respecté pour les classes dont la fonction machinChose utilise le retour co-variant, il n'y a aucun problème de conception à entrevoir
    LSP est un principe qui ne saurait être appliqué hors contexte, car le contexte apporte des contraintes et des garanties différentes, qui font que son application sera différente.
    Mais le contexte, c'est quoi selon toi

    C'est:
    1. un certain nombre de besoins à satisfaire
    2. un certain nombre de possibilité offertes par la conception Orientée Objet
    3. un certain nombre de règles, principes et lois à respecter afin d'effectuer la conception "selon les règles du lard"
    4. quelques restrictions aux possibilités offertes par la conception orientée objet due au langage utilisé (tel que l'impossibilité de recourir à l'héritage multiple en java)
    Mais, si tu dois effectivement tenir compte des restrictions qu'imposera le langage d'implémentation pour t'éviter d'avoir à "trouver le moyen de les contourner" au moment de l'implémentation, ce n'est absolument pas une raison pour accepter quelque chose que ton compilateur semble accepter alors que les règles que tu applique te pousse à le refuser.

    Prend le problème à l'envers, essaie de raisonner par l'absurde. Considère que tu VEUX changer la visibilité de la méthode foo dans B par rapport à A
    Je dirais de commencer par te poser la question de savoir s'il n'est pas plus opportun de faire en sorte que la fonction subisse les même restrictions d'accès dans A
    (je ne sais pas pourquoi tu veux faire une chose pareille, c'est sûrement une erreur de conception, mais pourquoi pas ).
    Ce n'est pas peut-être, c'est surement une erreur de conception, et c'est LSP qui te permet de t'en rendre compte...
    L'application du LSP va te dire que pour toute fonction faisant appel à foo() avec un A, il faut que ça continue de fonctionner si on passe un B à la place du A. Ca tombe plutôt bien, c'est bien le cas en C++...
    Si ce n'est que tu ne dois pas te baser sur le fait que le langage accepte sans broncher tes propres erreurs de conception pour te dire que ce n'en est pas, parce qu'aucun langage ne dispose de la capacité de vérifier pour toi si la décision de faire hériter une classe d'une autre est opportune ou non.

    Tous les langages estiment que, si tu prend la décision de faire hériter une classe d'une autre, c'est que tu as tes raisons qui sont fatalement valables et cohérentes avec les besoins que tu veux satisfaire.

    De la même manière, tu ne trouvera aucun langage qui puisse t'indiquer qu'il n'est pas opportun d'incrémenter un compteur à un instant précis de la logique, mais qu'il serait préférable de le faire XXX instructions plus tôt ou plus tard.

    A partir de là, si la décision est inopportune, tant pis pour toi, tu "NAKAVAIS" réfléchir d'avantage avant de prendre la décision.
    Pour en revenir à ton exemple, je n'ai pas de blocage à faire dériver voiture de animal si, dans mon contexte, cela a du sens (j'ai dû mal à trouver un tel contexte, cela dit).
    Il est peut être possible de trouver une contexte dans lequel cela aurait un sens, mais, de manière générale, il faut quand même admettre que la simple sémantique du terme voiture est beaucoup trop éloignée de celle du terme animal pour que cela soit accepté.

    Tu ne peux en effet que rarement répondre par l'affirmative à une question proche de "puis-je réellement estimer d'un point de vue sémantique qu'une voiture est un animal"

    Pour les cas les plus tendancieux, pour lesquels la sémantique des différentes classes est suffisamment proche, tu appellera... LSP à la rescousse pour t'aider à trancher
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #73
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Mais le contexte, c'est quoi selon toi
    C'est:
    1. un certain nombre de besoins à satisfaire
    Répondre à la question posée dans le premier post de cette thread

    2. un certain nombre de possibilité offertes par la conception Orientée Objet
    Les possibilités de C++

    3. un certain nombre de règles, principes et lois à respecter afin d'effectuer la conception "selon les règles du lard"
    Un changement de visibilité de fonction virtuelle

    4. quelques restrictions aux possibilités offertes par la conception orientée objet due au langage utilisé (tel que l'impossibilité de recourir à l'héritage multiple en java)
    Les restrictions de C++

    Citation Envoyé par koala01 Voir le message
    Je dirais de commencer par te poser la question de savoir s'il n'est pas plus opportun de faire en sorte que la fonction subisse les même restrictions d'accès dans A
    Ce changement de restriction n'a pas à être opportun ou pas. C'est une condition préalable imposée par la problématique.

    Citation Envoyé par koala01 Voir le message
    Mais, si tu dois effectivement tenir compte des restrictions qu'imposera le langage d'implémentation pour t'éviter d'avoir à "trouver le moyen de les contourner" au moment de l'implémentation, ce n'est absolument pas une raison pour accepter quelque chose que ton compilateur semble accepter alors que les règles que tu applique te pousse à le refuser.
    Nous ne faisons qu'appliquer les règles qui découlent de la question traduite en C++.

    Pour le raisonnement et la démonstration par l'absurde, voir les précédents posts.

    Nous concluons:

    Tout changement de visibilité d'une fonction virtuelle n'implique pas forcément un viol du LSP.

    Autrement dit, tout changement de visibilité d'une fonction virtuelle n'est pas une condition suffisante pour violer le LSP

  14. #74
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Ce qui est décourageant, c'est que je ne sais plus comment faire pour te convaincre qu'il faut, effectivement, se poser les bonnes questions, mais qu'il faut, surtout, se les poser dans le bon ordre...

    Ainsi, le contexte dans lequel LSP doit être vérifié doit est que tu as déterminé un certain nombre de besoins qui ont été exprimés par le "client" qui souhaite une nouvelle application.

    Sur base de ces besoins exprimés, tu va réfléchir à une série de classes qui, au travers des services qu'elles rendent, participent au fait de rencontrer tout ou partie des besoins exprimés, le tout, en veillant à te prémunir contre le risque de devoir "tout casser" quand un nouveau besoin plus ou moins transversal par rapport aux autres est exprimé.

    Comme tout ne vaut, en définitive, que par l'utilisation qui en est faite, tu dois commencer par réfléchir en termes totalement indépendants du langage dans lequel tu fournira ton application, en appliquant de manière stricte certains principes, règles ou loi comme Demeter, Open Close ou... LSP.

    Pour chaque décision de base, tu commence donc par te poser la question "puis-je faire ceci en vertu de demeter /du principe Open Close / du principe d'encapsulation / du principe de Liskov / autre (selon le cas)" de manière totalement indépendante du langage utilisé

    Ce n'est que si, et seulement si, le principe ou la règle général(e) de conception adapté te permet d'envisager quelque chose qu'il devient opportun de s'intéresser aux particularités du langage utilisé afin de savoir si ce dernier te permet de recourir à la technique envisagée.

    Il peut, en effet, arriver que le langage pose certaines restrictions à la mise en oeuvre de certaines technique ( "Mince, un héritage multiple aurait été particulièrement intéressant et tout à fait valide dans tel cas... Pas de bol, XXX ne me permet pas l'héritage multiple" ) et que tu doive donc trouver une autre solution "la moins mauvaise possible" à défaut d'utiliser la "meilleure" qui ne t'est pas autorisée.

    Mais, de l'autre coté, une décision conceptuelle inopportune / mauvaise / inadaptée restera inopportune, mauvaise ou inadaptée dans toutes les langues de l'arc-en-ciel et le fait que le langage te permette de la mettre en oeuvre n'en fera pas une "bonne" décision pour autant: c'est un fait à classer dans les "cas peau de banane" qui ne manqueront pas de te faire glisser à la première occasion.

    Si tu te base sur ce qui est autorisé par le langage avant de déterminer l'opportunité ou la validité d'une décision, tu ne pourra jamais en arriver à la conclusion que "non, je ne peux décemment pas appliquer telle ou telle technique" parce que "c'est autorisé par le langage, je ne vois pas pourquoi je m'en priverais", et, au final, tu te retrouves dans des situations dans lesquelles il n'y a plus rien de logique ou dans lesquelles tu peux invoquer des comportements qui n'ont strictement aucun sens pour l'objet réellement manipulé.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #75
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ce qui est décourageant, c'est que je ne sais plus comment faire pour te convaincre qu'il faut, effectivement, se poser les bonnes questions, mais qu'il faut, surtout, se les poser dans le bon ordre...
    Et moi, je ne sais plus comment faire pour que tu essaies d'envisager les choses sous un autre angle que celui que tu abordes .

    Pour chaque décision de base, tu commence donc par te poser la question "puis-je faire ceci en vertu de demeter /du principe Open Close / du principe d'encapsulation / du principe de Liskov / autre (selon le cas)" de manière totalement indépendante du langage utilisé
    Tu ne peux pas, car les mécanismes intrinsèques du langage vont introduire des comportements, comportements qui sont forcément à intégrer dans ta conception. L'idée d'une conception indépendante de tout langage n'existe que parce qu'il y a beaucoup de similitudes entre les langages. Tant que tu restes dans ce carcan de similitudes, tu peux être "indépendant du langage". Ici, on est clairement dans quelque chose de propre à C++.

    Par rapport à ta réponse précédente, j'ai parlé de covariance des arguments, tu m'as répondu covariance des valeurs de retour (dont il est généralement acquis qu'elle ne viole pas le LSP). Relis mon message précédent, et dis moi où je me trompe en affirmant qu'en multiple dispatch, les paramètres covariants ne violent pas le LSP alors qu'ils le font en single dispatch ?

    Il peut, en effet, arriver que le langage pose certaines restrictions à la mise en oeuvre de certaines technique ( "Mince, un héritage multiple aurait été particulièrement intéressant et tout à fait valide dans tel cas... Pas de bol, XXX ne me permet pas l'héritage multiple" ) et que tu doive donc trouver une autre solution "la moins mauvaise possible" à défaut d'utiliser la "meilleure" qui ne t'est pas autorisée.
    Le langage n'offre pas que des restrictions. Il offre des possibilités. La conception est nécessairement fonction de ces différentes possibilités (on ne conçoit pas de la même manière si on cible Ocaml ou java).

    Si tu te base sur ce qui est autorisé par le langage avant de déterminer l'opportunité ou la validité d'une décision, tu ne pourra jamais en arriver à la conclusion que "non, je ne peux décemment pas appliquer telle ou telle technique" parce que "c'est autorisé par le langage, je ne vois pas pourquoi je m'en priverais", et, au final, tu te retrouves dans des situations dans lesquelles il n'y a plus rien de logique ou dans lesquelles tu peux invoquer des comportements qui n'ont strictement aucun sens pour l'objet réellement manipulé.
    On ne parle pas de dire que c'est autorisé par le langage donc c'est bien. On parle de dire que dans le contexte lié à ce langage, telle chose est correcte et ne pose pas de problème particulier.

    Je vais te donner un dernier exemple. Suppose que tu veuilles modéliser un graphe. En java ou C#, tu sais que tes objets sont garbages collectés. Tu vas donc pouvoir modéliser ton graphe sous la forme d'objets noeuds, qui possèdent chacun une liste d'autres objets noeuds atteignables. Et tu ne te préoccupes absolument pas de savoir quand un noeud doit être détruit, car il sera de toute manière garbage collecté. En C++, tu ne peux pas passer sur cette contrainte, tu es obligé de revoir ta conception. Pourquoi ? Parce que le contexte lié au langage est différent, et qu'il amène des mécanismes qui font qu'une même conception est valable pour l'un et pas pour l'autre.

    La conception indépendante de tout langage, c'est à mon avis une belle illusion, qui s'effrite d'autant plus que tu pratiques des langages éloignés les uns des autres. Même si certains principes sont universels, leur application peut différer.

  16. #76
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ce qui est décourageant, c'est que je ne sais plus comment faire pour te convaincre [...]
    Tu n'arriveras pas à me convaincre. C'est trop tard

  17. #77
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Pour les paramètre covariant, il me semble que les langages qui les permettent par defaut utilsent un typage différent de celui de Liskov, donc le LSP n'a pas de raison d'être pour ces langages. Sinon montre moi une diagramme de classe qui met en oeuvre une technique pour résoudre un problème dispatch et montres moi la violation du LSP. (Si je prend les dispatchers de Loki, à part ta hiérachie qui doit respecter le LSP mais n'a pas de lien direct avec le dispatcher, aucune autre classe ne doit être hérité, donc pas de viole du LSP).

    Koala n'a pas dit qu'il n'y avait pas de cadre à l'application du LSP, mais qu'on ne devait pas tenir compte du langage. La seul restriction pour l'appliquer ca serait quelque chose comme : langage objet et typage selon la théorie de Liskov.

    Après le langage peut apporter certains restrictions (comme l'héritage multiple pour java), mais je vois difficilement comment il pourrait élargir des principes (ca serait plus un principe sinon).

    Ce changement de restriction n'a pas à être opportun ou pas. C'est une condition préalable imposée par la problématique.
    C'est justement ce que koala essay d'expliquer, cette problématique ne peut arriver car la question doit se poser au moment de la conception et cette volonté écarté. Si ta question est : est ce que je peus compiler sans problèmes en restreignant la visibilité ? alors la réponse est oui. Mais ce n'est pas la question, la question est bien de savoir si une restriction de visibilité fait sens au niveau du LSP ou non.

  18. #78
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Si ta question est : est ce que je peus compiler sans problèmes en restreignant la visibilité ? alors la réponse est oui. Mais ce n'est pas la question, la question est bien de savoir si une restriction de visibilité fait sens au niveau du LSP ou non.
    Non seulement ça compile, mais surtout ça fonctionne. La propriété du programme est toujours vraie après avoir effectué la substitution de type.

    Donc il existe au moins un programme dans lequel un changement de visibilité ne viole pas LSP. Cela suffit à en déduire que le changement de visibilité n'est pas une condition suffisante.

    Ca ne dit rien d'autre que ça.

  19. #79
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Bien que je sois de ceux qui tendent à penser qu'il y a faute de conception mais pas viol de LSP :
    Citation Envoyé par metagoto Voir le message
    Donc il existe au moins un programme dans lequel un changement de visibilité ne viole pas LSP. Cela suffit à en déduire que le changement de visibilité n'est pas une condition suffisante.
    Le principe dit pour tous les programmes. Donc cela ne devrait pas suffire à déduire notre (juste) cause

  20. #80
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Bien que je sois de ceux qui tendent à penser qu'il y a faute de conception [...]
    Pour ca on est tous d'accord je crois mais si la faute n'est pas un viol du LSP, où est le biais ? Quel loi/principe est violé ?

Discussions similaires

  1. Réponses: 2
    Dernier message: 02/10/2008, 17h37
  2. Fonction appelant une fonction virtuelle pure
    Par oodini dans le forum C++
    Réponses: 12
    Dernier message: 19/09/2008, 09h24
  3. Une fonction virtuelle ne peut pas retourner un template!
    Par coyotte507 dans le forum Langage
    Réponses: 10
    Dernier message: 08/02/2008, 21h39
  4. Problème de visibilité d'une fonction
    Par hello2lu dans le forum VBA Access
    Réponses: 8
    Dernier message: 03/07/2007, 16h20
  5. Réponses: 2
    Dernier message: 05/03/2006, 20h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo