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

C++ Discussion :

Programmation par contrat, application au C++


Sujet :

C++

  1. #1
    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 Programmation par contrat, application au C++
    Bonjour,

    J'ai écrit un article sur la programmation par contrat et sa mise in œuvre en C++. Ça se trouve ici :

    http://julien-blanc.developpez.com/a...rat_cplusplus/

    Citation Envoyé par Le synopsis
    Ce tutoriel vise à présenter de manière relativement concise les objectifs de la conception et de la programmation par contrat, ainsi que les techniques de mise en oeuvre dans le langage C++. Le lecteur est supposé connaître les bases de la programmation, de l'approche orientée objet et de la généricité. Ce tutoriel s'adresse donc à des développeurs de niveau moyen à expérimenté.
    Vos remanques sont évidemment les bienvenues, et bonne lecture.

  2. #2
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    (en anglais, on utilise le terme plus heureux de design by contracts)
    C'est design by contract sans le s.

    Sinon dans l'exemple de 5.3 il y a do_f qui se transforme en _f.

    MAT.

  3. #3
    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
    Corrigé, merci

  4. #4
    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
    Bonjour,
    En tout cas, c'est un super article
    La programmation par contrat est une démarche qui permet de faire des codes plus simples en clarifiant les responsabilités. Ses principes se heurtent trop souvent à l'habitude de la programmation défensive et c'est dommage.
    Il y a peu de littérature en français et sur le net sur ce sujet. On a enfin un document qui précise bien la démarche.

  5. #5
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Très bon tutoriel, merci (surtout que suite à la discussion levée par Archi je n'été pas arriver à assez me renseigner à mon gout)!
    Par contre :
    laissant les appels virtuels à des méthodes protégées.
    Ca ne serait pas plutôt privées ? Même si ce n'est pas ce que tu voulais dire, je trouve que "protégées" ça fait trop pensées à "protected".

  6. #6
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    Juste pour ton probleme avec le probleme du return multiple, j'aurais peut etre une solution (l'exemple est moche mais c'est l'idee qui compte ) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int A::f(int n){
       int ret;
       ENSURE_RET(int, ret, (*_r) >= -2 && (*_r) < 1, "Valeur de retour dans l'intervalle [-2, 1]");
       if(n > 0){
          ret = 1/n;
          return ret;
       }
       else{
          ret = 2/n;
          return ret;
       }
    }
    avec

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #define ENSURE_RET(type, value, cond, text) \
       class EnsureRet{ \
          EnsureRet(type* value) \
             :_r(value) \
          {} \
     \
          ~EnsureRet(){ \
             ENSURE(cond, text); \
          } \
     \
          type* _r; \
       } ensure_ret_instance(&value);
    L'idee est juste de creer une instance en debut de fonction/methode qui effectuera les checks lors de sa destruction (et donc a la fin de la fonction)

    Apres l'idee peut etre largement amelioree

  7. #7
    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 Lavock Voir le message
    Par contre :
    laissant les appels virtuels à des méthodes protégées.
    Ca ne serait pas plutôt privées ? Même si ce n'est pas ce que tu voulais dire, je trouve que "protégées" ça fait trop pensées à "protected".
    Je ne suis pas fan de la visibilité privée, donc j'entendais bien protected (et puis, j'ai été longtemps persuadé qu'une méthode privée n'était pas redéfinissable, ce qui est faux mais ça crée des habitudes). Ici, je trouve intéressant de laisser la possibilité à l'auteur d'une classe dérivée d'appeler directement la méthode qui ne vérifie pas le contrat. Mais je suis d'accord que les deux points de vue se défendent. Le NVI tel que décrit au départ par James Kanze (je suis d'ailleurs désolé pour lui, mais je n'ai pas trouvé d'article de sa part à citer, seulement de nombreux messages épars sur des newsgroups, si quelqu'un en connaît un, je le rajouterai volontiers) utilise effectivement la visibilité privée. Son argument est que le fait que le client hérite de la classe ne change rien au fait que ce soit un client, et donc, qu'on doit vérifier le contrat si la vérification est active pour tous.

    L'idee est juste de creer une instance en debut de fonction/methode qui effectuera les checks lors de sa destruction (et donc a la fin de la fonction)
    C'est tentant, mais malheureusement, ça ne fonctionne pas. En effet, les postconditions ne sont pas garanties en cas d'exception, donc les vérifier dans un destructeur n'est pas faisable. C'est éventuellement envisageable pour les invariants, suivant le comportement qu'on souhaite avoir en cas d'exception.

  8. #8
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Dans ce cas, peut-être faudrait-il le précisée quelque part... Le lien vers la faq dit exactement le contraire quand même (non-pas que je veuille défendre l'un ou l'autre point de vue).

    Citation Envoyé par thoratou Voir le message
    L'idee est juste de creer une instance en debut de fonction/methode qui effectuera les checks lors de sa destruction (et donc a la fin de la fonction)

    Apres l'idee peut etre largement amelioree
    Je vois pas ce qui empêche de mettre plusieurs ENSURE dans une fonction si tu met plusieurs return. Au pire des cas, reste le tout bête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     #define ENSURE_RET(ret,cond,text) ENSURE(cond,text) ; return ret
    Voir même en mettant un nom plus accessible style ereturn/endf ou quelque-chose du genre... Après tout, quelque-soit le résultat, il se termine part l'arrêt de la fonction...

  9. #9
    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
    Dans ce cas, peut-être faudrait-il le précisée quelque part... Le lien vers la faq dit exactement le contraire quand même (non-pas que je veuille défendre l'un ou l'autre point de vue).
    Ça me semble raisonnable. En fait, maintenant que j'y repense, on m'avait déjà fait la remarque pendant la relecture, j'ai corrigé le code (parce que je n'y tiens pas plus que ça, à ma visibilité protégée, et pour être cohérent avec la FAQ), et j'ai oublié de modifier le texte. Je vais changer ça, ça sera plus clair et évitera les questions existentielles.

    Je vois pas ce qui empêche de mettre plusieurs ENSURE dans une fonction si tu met plusieurs return. Au pire des cas, reste le tout bête :
    Code :

    #define ENSURE_RET(ret,cond,text) ENSURE(cond,text) ; return ret

    Voir même en mettant un nom plus accessible style ereturn/endf ou quelque-chose du genre... Après tout, quelque-soit le résultat, il se termine part l'arrêt de la fonction...
    Si tu as plusieurs closes ENSURE identiques, ça va faire des choses bizarres au niveau de doxygen. Et puis, tu risques la désynchronisation. Ça ne me plaît pas du tout. La macro ne marche pas, parce qu'il faut en définir suffisamment pour pouvoir gérer n postconditions, et que tu as le même risque de désynchronisation. La bonne solution pour ce problème, c'est le NVI . On peut s'amuser à en chercher d'autres, mais il n'y a à ma connaissance rien de simple à mettre en œuvre qui règle tous les problèmes.

  10. #10
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Si tu as plusieurs closes ENSURE identiques, ça va faire des choses bizarres au niveau de doxygen.
    Compris.
    Citation Envoyé par white_tentacle Voir le message
    Et puis, tu risques la désynchronisation.
    Moins compris >< ! Nul part tu parles de synchronisation. Qu'est-ce que ça va désynchronisé ?

  11. #11
    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
    Moins compris >< ! Nul part tu parles de synchronisation. Qu'est-ce que ça va désynchronisé ?
    Quelque chose de ce genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int fonction_stupide(int a)
    {
        REQUIRE(a > 0);
        int ret;
        if(a > 5)
        {
            ret = 4;
            ENSURE(ret > 0);
            return ret;
        }
        else
        {
            ret = -2;
            ENSURE(ret < 0);
            return ret;
        }
    }
    Là tu ne sais plus quel est le contrat de ta fonction, tu as deux clauses ensure qui sont différentes, et en plus contradictoire (en fait, dans le cas présent la vraie postcondition c'est ret != 0). Si tu dupliques tes clauses ENSURE, tu as la certitude qu'à un moment donné de l'évolution du produit, quelqu'un fera quelque chose de ce genre.

  12. #12
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    D'ou le ENSURE_RET qui resoud ce probleme de desynchronisation.
    La levee d'une exception ne doit servir que dans le cas de scenarii non nominaux, sortant donc egalement de tout contrat de ce niveau. Je ne vois donc pas en quoi le fait de verifier ou pas une post-condition dans le cas d'une levee d'exception pose probleme.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    int fonction_stupide(int a)
    {
        REQUIRE(a > 0);
        int ret;
        ENSURE_RET(ret != 0);
        if(a > 5)
        {
            ret = 4;
            return ret;
        }
        else
        {
            ret = -2;
            return ret;
        }
    }

  13. #13
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    /me est convaincu >< !
    C'est de l'idiot-proofisation, mais c'est un autre débat !

    La seul chose qui me dérange, c'est qui dit vouloir des bonne perf avec le NVI dit apparition d'inlining massif pour éviter le drame... Qui dit inlining massif, dit erf à la jolie compilation bien séparé... Ou alors bienvenue au maux de tête (je suis plutôt dans le deuxième cas personnellement).

    En même temps, qui irait s'amuser à faire de la programmation par contrat sur un truc qui à besoin de perf...
    ...
    ...
    ...
    ...
    Euh... moi ! (ou comment vouloir le beurre, l'argent du beurre et la crémière et sans me fouler ><)

  14. #14
    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
    Citation Envoyé par thoratou Voir le message
    Je ne vois donc pas en quoi le fait de verifier ou pas une post-condition dans le cas d'une levee d'exception pose probleme.
    En cas de sortie par une exception, tu es amené à vérifier une post condition à un moment où elle n'a pas forcément à être remplie. Je crois comprendre que c'est ce cas qui peut poser problème dans le sens où il vient 'perturber' la logique de la vérification : si check(postcondition)==false ==> erreur (bug!) du fournisseur. Là, la postcondition peut être KO sans que ce soit une erreur du fournisseur, mais simplement un autre problème. Prenons l'exemple du retrait d'une clé USB contenant un fichier accédé par la fonction : ce n'est pas un bug de la fonction, donc ça génère une exception mais les postsconditions ne sont probablement pas vérifiées.

  15. #15
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par thoratou Voir le message
    D'ou le ENSURE_RET qui resoud ce probleme de desynchronisation.
    La levee d'une exception ne doit servir que dans le cas de scenarii non nominaux, sortant donc egalement de tout contrat de ce niveau. Je ne vois donc pas en quoi le fait de verifier ou pas une post-condition dans le cas d'une levee d'exception pose probleme.
    Tu va renvoyer une exception dans l'exception >< ? Problème de masquage peut-être...

  16. #16
    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
    La levee d'une exception ne doit servir que dans le cas de scenarii non nominaux, sortant donc egalement de tout contrat de ce niveau. Je ne vois donc pas en quoi le fait de verifier ou pas une post-condition dans le cas d'une levee d'exception pose probleme.
    En fait, raisonne par l'absurde.

    Suppose que tu as une postcondition sur ta valeur de retour.
    Suppose que ta fonction lance une exception
    --> alors elle n'a pas de valeur de retour
    --> donc elle ne peut pas garantir sa postcondition, puisqu'elle porte sur une valeur qui n'existe pas. Elle ne peut pas non plus tester si elle remplit bien sa part du contrat, puisque le contrat porte sur quelque chose qui n'existe pas.

    On arrive alors à un cas qu'on ne peut pas régler. La seule solution, c'est que la fonction ne garantisse pas ses postconditions en cas d'exception. Ce qui nous empêche d'utiliser une approche basée sur le destructeur (il est faux de vérifier qu'on garantit quelque chose qu'on ne garantit pas).

  17. #17
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Je suis en train de lire l'article. C'est très intéressant et très facile à lire, bravo .

    Je souhaite seulement notifier la présence d'une coquille :
    Ce sont donc deux postconditions, qui sont exprimées par l'usage de const. Là encore, ces contrats sont garantis par le compilateur (modulo détournement volontaire au moyen de volatile ou const_cast).
    N'est-ce pas plutôt mutable que tu voulais dire ?

    Il y a aussi quelques &amp; dans les codes sources.

Discussions similaires

  1. [Eiffel] Programmation par contrats
    Par SkIllz2k dans le forum Autres langages
    Réponses: 1
    Dernier message: 02/05/2005, 20h05
  2. [Tests]La programmation par contrats
    Par fabien.raynaud dans le forum Test
    Réponses: 6
    Dernier message: 26/07/2004, 11h06
  3. Programmation par module : applications multilingues
    Par argoet dans le forum Langages de programmation
    Réponses: 13
    Dernier message: 03/02/2004, 11h28

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