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 :

Quand les mutateurs nous mentent


Sujet :

C++

  1. #1
    Membre actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2008
    Messages
    132
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2008
    Messages : 132
    Points : 290
    Points
    290
    Par défaut Quand les mutateurs nous mentent
    [EDIT]Cette discussion est un fork de la discussionhttp://www.developpez.net/forums/d12...te-debutants-c de manière à recentrer le débat, n'hésitez pas à intervenir dans les deux discussions mais en veillant à ne pas les mélanger [/EDIT]

    Bon, je rêve ou bien je lis qu'en gros il ne faut plus faire du C parce que le C++ fait la même chose et plus encore?
    Pour le fait que le C++ touche plus de paradigmes, est plus simple à apréhender .. etc, pas de problème. Mais qu'il puisse se substituer à C, c'est juste une connerie équivalente à dire que l'on peut substituer MongoDB à MySQL.
    J'ai la flemme d'expliquer en détail mes propos .. je peux juste balancer un exemple: besoin d'un programme "compilé" prenant le moins d'espace possible.

    Aussi, l'utilité d'utiliser des getter/setter est un maintenance plus aisée du code. Exemple débile en Java (ne pas faire attention à la division d'un ingredient par un entier):
    1ere version:
    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    class CocaColaDuMcdo extends Drink
    {
      private Ingredient eau;
      private Ingredient ingredientPrincipal;
      private Ingredient ingredientX;
      private Ingredient ingredientY;
     
      public CocaColaDuMcdo(Ingredient eau, Ingredient ingredientPrincipal, Ingredient ingredientX, Ingredient ingredientY)
      {
        setIngredientPrincipal(ingredientPrincipal);
        .
        .
        .
      }
     
      private Drink buildDrink()
      {
        this.getIngredientPrincipal() + this.getIngredientX() + ...
      }
     
      public Ingredient getIngredientPrincipal()
      {
        return this.ingredientPrincipal;
      }
     
      public setIngredientPrincipal(Ingredient ingredientPrincipal)
      {
        this.ingredientPrincipal = ingredientPrincipal;
      }

    2ieme version (histoire de commencer l'arnaque):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public setIngredientPrincipal(Ingredient ingredientPrincipal)
    {
      this.ingredientPrincipal = ingredientPrincipal / 2;
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par nickyla Voir le message
    Bon, je rêve ou bien je lis qu'en gros il ne faut plus faire du C parce que le C++ fait la même chose et plus encore?
    Oui, tu rêves...

    Personne n'a jamais dit qu'il fallait abandonner C
    Pour le fait que le C++ touche plus de paradigmes, est plus simple à apréhender .. etc, pas de problème. Mais qu'il puisse se substituer à C, c'est juste une connerie équivalente à dire que l'on peut substituer MongoDB à MySQL.
    J'ai la flemme d'expliquer en détail mes propos .. je peux juste balancer un exemple: besoin d'un programme "compilé" prenant le moins d'espace possible.
    Mais comme tu rêves, quelle importance, hein
    Aussi, l'utilité d'utiliser des getter/setter est un maintenance plus aisée du code.
    Heuu... une quoi

    Il est vrai que, comme tu vas, souvent, devoir commencer par appeler l'accesseur pour récupérer la valeur d'origine et que toute la logique qui modifie cette valeur d'origine sera sans doute répétée de gauche et de droite, tu vas en effet avoir une maintenance beaucoup plus aisée

    Après cela, tu t'étonneras surtout qu'une correction s'applique si tu suis le chemin A mais que le chemin B continue à n'en faie qu'à sa tête
    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. #3
    Membre actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2008
    Messages
    132
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2008
    Messages : 132
    Points : 290
    Points
    290
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Et ça ne te pose pas de problème d’avoir une fonction menteuse ? (le nom dit une chose, le code en fait une autre).

    Moi, si…
    Même si mon exemple (j'ai bien précisé que c'était un exemple bidon non .. je vous sent un peu à cran) n'est pas parlant. Mon setter fait EXACTEMENT ce que son nom indique, il construit la valeur de mon attribut et la lui affecte. La sémentique du comment il l'affecte, c'est son affaire. Je lui dit de définir la valeur de l'ingrédient principal. S'il veut la couper, il la coupe.

  4. #4
    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 nickyla Voir le message
    Même si mon exemple (j'ai bien précisé que c'était un exemple bidon non .. je vous sent un peu à cran) n'est pas parlant. Mon setter fait EXACTEMENT ce que son nom indique, il construit la valeur de mon attribut et la lui affecte. La sémentique du comment il l'affecte, c'est son affaire. Je lui dit de définir la valeur de l'ingrédient principal. S'il veut la couper, il la coupe.
    T’as pas compris où je voulais en venir. Mais honnêtement, quand je vois ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    public void setIngredientPrincipal(Ingredient ingredientPrincipal) {}
    public Ingredient getIngredientPrincipal() const {}
    Je m’attends à ce que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Ingredient poireau; // note : sémantique de valeur
    Recette soupe; // note : sémantique d’entité
    soupe.setIngredientPrincipal(poireau);
    assert(soupe.getIngredientPrincipal() == poireau);
    Si ce n’est pas le cas (ce n’est pas le cas dans ton exemple), ta fonction est menteuse. Et ça de mon point de vue c’est très mal .

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Le verbe dans le nom de la fonction, c'est set, pas copy.

    Pour définir le membre, on a besoin d'un argument. Rien dans la sémantique du mot set ne dit que que cela sera une copie.

    On s'est peut-être trop habitué, à tort, à ce que set désigne un bête mutateur.

    Moi aussi, je m'attendrais à ce que soit une copie. Mais aurais-je raison ?

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Ce qui me choque le plus dans cette méthode c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.ingredientPrincipal = ingredientPrincipal / 2;
    Quel signification a de diviser un ingrédient par deux ?

    Je trouve que l'exemple est mal choisit et je pense qu'on utiliserais plus une méthode "add" qu'une méthode "set" pour effectuer cette action.
    Avec un ingrédiant contenant une quantité et une méthode pour en prélever une certaine quantité ou proportion.

    Par contre on peut envisager une classe avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void setGravity(Newton force)
    {
           m_poids = m_masse * force;
    }
    Bon ce n'est qu'un exemple, j'espère ne pas me tromper sur la formule

  7. #7
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Sauf que c'est le poids qui est changé...
    J'ai l'impression que certains d'entre nous ont souvenir d'un article profondément gravé en eux et d'autres ... sont plus cavaliers dans leur nommage.
    -> http://blog.emmanueldeloget.com/inde...des-accesseurs
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    D'après cet article, set signifie "initialiser avec une valeur spécifiée".

    Mais spécifiée par quoi ? L'argument ou le code ? Le site d'Oxford Dictionnary, donné en lien, le ne dit pas...

    Pour moi, c'est surtout une question d'usage.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par oodini Voir le message
    D'après cet article, set signifie "initialiser avec une valeur spécifiée".

    Mais spécifiée par quoi ? L'argument ou le code ? Le site d'Oxford Dictionnary, donné en lien, le ne dit pas...

    Pour moi, c'est surtout une question d'usage.
    Tu bloques, comme cela t'arrive régulièrement, sur un détail et tu laisses encore une fois l'arbre cacher la forêt.

    Le fait des mutateurs est que, quoi que puisse vouloir dire "set":
    1. Cela oblige l'utilisateur à connaitre un type utilisé par l'objet sur lequel il agit, contrevenant à la loi demeter
    2. Cela donne à l'utilisateur de l'objet qui expose cette fonction des responsabilité qu'il ne devrait pas avoir (calculer la valeur à itnialiser, vérifier que cette valeur soit cohérente,...)
    3. Afin de pouvoir fournir une valeur correcte, l'utilisateur devra très régulièrement récupérer la "valeur d'origine"
    4. du (2) découle le fait que la logique se trouve (sans doute) dupliquée à différents endroits, ce qui, en cas de correction ne tardera pas à provoquer des incohérences (le chemin A occasionnant un résultat différent du chemin B)
    5. Si la fonction fait plus que simplement initialiser la valeur, le nom de la fonction "ment" à l'utilisateur de l'objet quant ce qui est effectivement effectué
    6. "set" donne une impression "d'instantanéité" qui n'est pas *forcément* juste
    7. les mutateurs correspondent régulièrement à un ensemble de comportements plus restreints mais inversés (setEnabled(bool) qui correspond aussi bien à enable qu'à disable ou setFont qui va modifier aussi bien la police de caractères que sa taille, son état "gras","soulingé", "italique", etc )
    Le fait de remplacer le mutateur par d'autres comportements corrige tous ces problèmes
    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

  10. #10
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Sauf que c'est le poids qui est changé...
    Si on modifie la gravité, il est évident que le poids serait changé sinon l'objet serait dans un état incohérent.
    Quand on mange une part de gâteau, on va modifier son volume et sa masse.
    Après, si on a pas besoin de récupérer/d'utiliser la gravité exercée sur l'objet, pourquoi la stocker ?

    Citation Envoyé par Luc Hermitte Voir le message
    J'ai l'impression que certains d'entre nous ont souvenir d'un article profondément gravé en eux et d'autres ... sont plus cavaliers dans leur nommage.
    -> http://blog.emmanueldeloget.com/inde...des-accesseurs
    C'est un article très intéressant et je comprend mieux où vous voulez en venir.
    En effet, je ne pensais pas que "set" avait une définition aussi précise.

    D'après ce que j'ai lu et ce que j'en pense, un bon setter devrait :
    - mettre l'objet dans l'état spécifié ou lancer une exception/ retourner false le cas échéant ;
    - que la valeur passée à un setter ne dépende pas de la valeur précédente.


    Citation Envoyé par Koala01
    Si la fonction fait plus que simplement initialiser la valeur, le nom de la fonction "ment" à l'utilisateur de l'objet quant ce qui est effectivement effectué
    Je ne suis pas d'accord, set veut dire "mettre dans un état spécifié" si j'ai bien compris, mais mettre un objet dans un état différent ne se résume pas uniquement à modifier une variable donc je trouve que la fonction ne "ment" pas dans ce sens.
    Citation Envoyé par Koala01
    "set" donne une impression "d'instantanéité" qui n'est pas *forcément* juste
    Personnellement je n'ai pas ce genre d'appriori à ce sujet, un "set" prendra le temps qu'il faut. Si nécessaire on rajoute une indication dans la doc.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je ne suis pas d'accord, set veut dire "mettre dans un état spécifié" si j'ai bien compris, mais mettre un objet dans un état différent ne se résume pas uniquement à modifier une variable donc je trouve que la fonction ne "ment" pas dans ce sens.
    Imagines une fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Shape::setBottomLeft(Position const & pos)
    {
        bottomLeft_ = pos;
    }
    Nous sommes bien d'accord qu'elle ne fait exactement que ce qu'elle prétend faire

    Modifions la un tout petit peu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Shape::setBottomLeft(Position const & pos)
    {
        if( pos.x() > XMAX ||
            pos.y() > YMAX )
        {
            return; 
            /* idéalement throw BadPosition(pos); */
        }
        botomLeft_ = pos;
        computeBoundingBox();
    }
    Et là, j'ai deux question à te poser:
    • Qu'est ce qui indique, dans setBottomLeft, à l'utilisateur que la fonction va s'assurer que la position est correcte
    • Qu'est ce qui indique, dans setBottomLeft, à l'utilisateur que la fonction va recalculer le bounding box
    Comme la fonction en fait plus que ce qu'elle ne le dit, aussi bien pour le test de validité que pour l'appel à computeBoundingBox, elle ment à l'utilisateur qui ne s'en rendra compte que s'il décide d'aller en voir l'implémentation

    Tu me diras sans doute que "oui, mais ce n'est pas si grave, il faut mieux cela que d'avoir une valeur invalide"

    Mais, si tu acceptes ce mensonge, sommes toutes minime, cela t'ouvre la voie royale vers des mensonges plus importants sous prétexte que "bah, on l'a déjà fat avec setBottomLeft"

    Qu'est ce qui t'empêcherait de donner un nom plus spécifique

    Personnellement je n'ai pas ce genre d'appriori à ce sujet, un "set" prendra le temps qu'il faut. Si nécessaire on rajoute une indication dans la doc.
    Prenons un exemple similaire:

    Si tu lis Shape::SetPosition(Position const &), tu vas te dire que cette fonction "déplace ton shape vers la postion indiquée".

    Comme le but de cette fonction est clair pour toi, tu n'iras pas forcément voir au niveau de la documentation ce qui est dit sur le sujet

    Tu t'attendras donc, en toute logique, à ce que ce soit simplement implémenté sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Shape::setPosition(Position const & pos)
    {
        topLeft_ = pos;
        /* au fait, on s'attend à ce que bottomRight_ reste inchangé :? */
    }
    Bref, tu t'attend à ce que la position soit, à un instant donné, la position d'origine et, tout de suite après, la nouvelle position.

    Tu n'as, encore une fois, aucune indication qui te permette d'envisager le fait que tu vas déplacer "progressivement" topLeft_ vers la nouvelle positon, ni sur ce qu'il advient de bottomRight_;

    Par contre, si tu renommes cette fonction en moveTo(Position const & pos):
    1. Tu sais très bien ce qu'il adviendra de bottomRigh_ car on ne parle que de mouvement (on est donc en droit d'estimer que bottomRight_ sera modifié de manière à garder les mêmes dimensions)
    2. On se rend beaucoup plus facilement compte qu'il s'agit d'un mouvement, et l'on est conscient du fait qu'un mouvement n'est *pas forcément* instantané. Cela nous incitera sans doute à aller voir dans la doc si le mouvement se fait de manière instantanée ou pas (à moins qu'il n'y ait une fonction moveToAnimated ou un état correspondant au fait que les modifications soient animée ou non )
    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

  12. #12
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    [*]Qu'est ce qui indique, dans setBottomLeft, à l'utilisateur que la fonction va s'assurer que la position est correcte
    Le prototype peut prendre les exceptions pouvant éventuellement être jetées (throws me semble (?) ).
    Sinon le set peut retourner un booléen.
    Mais en aucun cas faire un return tout court cf post précédant.

    Citation Envoyé par koala01 Voir le message
    [*]Qu'est ce qui indique, dans setBottomLeft, à l'utilisateur que la fonction va recalculer le bounding box
    Si il y a un bounding box, il y a plus que probablement des méthodes en relation avec cette bounding box (collisions, getArea(), ... ), il est donc évident que la bounding box sera recalculée pour garder un état de l'objet cohérent.

    Citation Envoyé par koala01 Voir le message
    [/LIST]Comme la fonction en fait plus que ce qu'elle ne le dit, aussi bien pour le test de validité que pour l'appel à computeBoundingBox, elle ment à l'utilisateur qui ne s'en rendra compte que s'il décide d'aller en voir l'implémentation
    Cet argument me parait un peu bizarre.
    L'encapsulation est censé être vu comme une "boîte noire", l'utilisateur ne devrait donc pas à avoir à savoir ce qu'il se passe exactement dans la méthode or tu pars du principe que l'utilisateur devrais savoir ce qu'il s'y passe mais qu'il ne devrait pas aller regarder le code.
    C'est comme les shared_ptr, sommes-nous censé savoir qu'il y a des shadow_ptr derrière ?
    Est-ce pour autant que les shared_ptr nous mentent?


    Citation Envoyé par koala01 Voir le message
    Mais, si tu acceptes ce mensonge, sommes toutes minime, cela t'ouvre la voie royale vers des mensonges plus importants sous prétexte que "bah, on l'a déjà fat avec setBottomLeft"
    <troll>C'est pas comme si certains langages même nous mentaient </troll>
    Si on devait interdire toutes les choses pouvant entraîner un abus, le C++ se retrouverait bien vide. Ne vaut-il pas mieux apprendre à les utiliser plutôt que de les éviter et ne pas savoir quoi faire lorsqu'il faudrait les utiliser ?
    N'est-ce pas une question de discernement ? de savoir ce qu'il faut faire et quand ?
    Après peut-on réellement considérer cela comme un mensonge ?
    Au sens de certains philosophe, ce qu'on ne dit pas est un mensonge mais dans ce cas là l'encapsulation même est un mensonge.
    Sinon si on considère que ne pas dire certaines choses n'est pas un mensonge, où avons-nous menti ? Rien ne dit que les "set" doivent être rapide et "instantané", ce sont des préjugés que les programmeurs ne devraient pas avoir. En effet, le code qu'on utilise n'est pas toujours propre à 100%, il faut bien être conscient que derrière une méthode on peut très bien avoir tout et n'importe quoi.
    Ex : On peut très bien invalider des itérateurs lorsqu'on insère des nouveaux éléments dans un conteneur.
    Sinon quel problème ceci pourrait générer ? Une perte de performance ?
    C'est tellement négligeable et ne dit-on pas que l'optimisation prématurée est diabolique ? Si on recherche l'optimisation, on verra bien lors des tests les fonctions qui posent réellement problème.

    Citation Envoyé par koala01 Voir le message
    Qu'est ce qui t'empêcherait de donner un nom plus spécifique

    Prenons un exemple similaire:

    Si tu lis Shape::SetPosition(Position const &), tu vas te dire que cette fonction "déplace ton shape vers la postion indiquée".

    Comme le but de cette fonction est clair pour toi, tu n'iras pas forcément voir au niveau de la documentation ce qui est dit sur le sujet

    Tu t'attendras donc, en toute logique, à ce que ce soit simplement implémenté sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Shape::setPosition(Position const & pos)
    {
        topLeft_ = pos;
        /* au fait, on s'attend à ce que bottomRight_ reste inchangé :? */
    }
    Bref, tu t'attend à ce que la position soit, à un instant donné, la position d'origine et, tout de suite après, la nouvelle position.

    Tu n'as, encore une fois, aucune indication qui te permette d'envisager le fait que tu vas déplacer "progressivement" topLeft_ vers la nouvelle positon, ni sur ce qu'il advient de bottomRight_;

    Par contre, si tu renommes cette fonction en moveTo(Position const & pos):
    1. Tu sais très bien ce qu'il adviendra de bottomRigh_ car on ne parle que de mouvement (on est donc en droit d'estimer que bottomRight_ sera modifié de manière à garder les mêmes dimensions)
    2. On se rend beaucoup plus facilement compte qu'il s'agit d'un mouvement, et l'on est conscient du fait qu'un mouvement n'est *pas forcément* instantané. Cela nous incitera sans doute à aller voir dans la doc si le mouvement se fait de manière instantanée ou pas (à moins qu'il n'y ait une fonction moveToAnimated ou un état correspondant au fait que les modifications soient animée ou non )
    Je trouve ton exemple pas très parlant.
    "Déplacer" un objet n'a pas la même signification que de le poser à un endroit donné.
    On peut très bien avoir des méthode move et des méthodes setPosition dans une même classe.
    Avec move, on effectue un "déplacement", un mouvement.
    Avec setPosition, on lui assigne une position, il n'y a pas vraiment de "mouvement".

    P.S. On dérive un peu du sujet originel, ne devrions-nous pas déplacer ce débat dans un autre sujet?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Le prototype peut prendre les exceptions pouvant éventuellement être jetées (throws me semble (?) ).
    cette manière est dépréciée au profit de nothrow (la seule spécification restante est le fait qu'une fonction s'engage éventuellement à ne pas lancer d'exception )
    Si il y a un bounding box, il y a plus que probablement des méthodes en relation avec cette bounding box (collisions, getArea(), ... ), il est donc évident que la bounding box sera recalculée pour garder un état de l'objet cohérent.
    Justement, non: une fonction set ne te donne pas ce genre d'information...

    Méfies toi de ce qui est "évident", ca ne l'est jamais autant que ce que l'on pourrait imaginer

    Cet argument me parait un peu bizarre.
    L'encapsulation est censé être vu comme une "boîte noire", l'utilisateur ne devrait donc pas à avoir à savoir ce qu'il se passe exactement dans la méthode or tu pars du principe que l'utilisateur devrais savoir ce qu'il s'y passe mais qu'il ne devrait pas aller regarder le code.
    Je pars du principe que l'utilisateur d'une classe n'a pas à aller voir le code qui se cache derrière une fonction pour pouvoir l'utiliser.

    Et je pars du principe que l'utilisateur n'ira pas voir la doc s'il croit avoir saisi le but poursuivi par une fonction, sur base de son nom.

    Je présumes que tu ne pourras pas faire autrement que d'être d'accord avec moi sur ces deux principes, non
    C'est comme les shared_ptr, sommes-nous censé savoir qu'il y a des shadow_ptr derrière ?
    Est-ce pour autant que les shared_ptr nous mentent?
    Ce n'est pas cela que je dis, je dis que l'on manipule des objets en invoquant des fonctions membres et que l'on s'attend donc à ce que le comportement observé corresponde au comportement l'on déduit "naturellement" du nom de la fonction que l'on appelle.

    L'utilisateur n'a pas plus à savoir qu'une variable est gérée sous la forme d'un pointeur intelligent qu'il n'a à s'inquiéter de savoir ce qu'une fonction fait effectivement du paramètre qui lui est passé.

    Mais, pour qu'il puisse ne pas avoir à s'inquiéter de ce genre de chose, il faut que les comportements que l'on met à sa disposition au travers de l'interface publique d'une classe soient suffisamment explicites pour ne laisser aucune ambiguïté quant au résultat qu'il obtiendra en les invoquant
    <troll>C'est pas comme si certains langages même nous mentaient </troll>
    Je ne vais pas nourrir celui-là
    Si on devait interdire toutes les choses pouvant entraîner un abus, le C++ se retrouverait bien vide. Ne vaut-il pas mieux apprendre à les utiliser plutôt que de les éviter et ne pas savoir quoi faire lorsqu'il faudrait les utiliser ?
    Je ne dis pas qu'il faut interdire les choses pouvant mener à des abus, je dis qu'il est de notre devoir de faire en sorte que l'utilisateur puisse utiliser ce qu'on lui fourni sans avoir à se poser de question... La nuance est de taille, non
    N'est-ce pas une question de discernement ? de savoir ce qu'il faut faire et quand ?
    Le discernement n'est que rarement un conseiller de première ordre, faut il te rappeler la fameuse discussion que l'on a eu concernant LSP

    Le fait de déterminer les services rendus par une classe se rapproche de la conception, et là, la rigueur est nécessaire
    Après peut-on réellement considérer cela comme un mensonge ?
    Comment appelles tu quelqu'un qui ne fait pas ce qu'il s'engage à faire
    Au sens de certains philosophe, ce qu'on ne dit pas est un mensonge mais dans ce cas là l'encapsulation même est un mensonge.
    Mensonge par omission, en effet...

    Mais tu te trompes de problème: L'encapsulation doit t'inciter à réfléchir en terme de services rendus et en terme de comportements.

    Si tu choisi correctement le nom de tes comportements plutôt que de céder à la facilité qui consiste à choisir un nom "générique", tu gagnes sur tous les tableaux:
    1. Tes comportements ne mentent plus sur ce qu'il font
    2. Tu ne donnes pas à l'utilisateur une responsabilité qu'il ne devrait pas avoir
    3. Tu évites les duplications de code, et tu t'assures donc que toute modification du comportement sera effective quel que soit le chemin qui t'amène à l'appeler (tu gagnes donc en cohérence et tu évites bien des régressions)
    4. Tu permets à l'utilisateur de se fier à ce qu'il déduit du nom du comportement


    Sinon si on considère que ne pas dire certaines choses n'est pas un mensonge, où avons-nous menti ? Rien ne dit que les "set" doivent être rapide et "instantané", ce sont des préjugés que les programmeurs ne devraient pas avoir.
    Mais qu'ils ont régulièrement: pourquoi se seraient ils cassé la tête à calculer la position autrement
    En effet, le code qu'on utilise n'est pas toujours propre à 100%, il faut bien être conscient que derrière une méthode on peut très bien avoir tout et n'importe quoi.
    Mais c'est ce qu'il faut éviter à tout prix si tu veux avoir un minimum de qualité dans ton travail !!!
    Ex : On peut très bien invalider des itérateurs lorsqu'on insère des nouveaux éléments dans un conteneur.
    Cela n'a rien à voir...

    L'invalidation des itérateur est la conséquence logique du concept mis en oeuvre par le conteneur envisagé
    Sinon quel problème ceci pourrait générer ? Une perte de performance ?
    C'est tellement négligeable et ne dit-on pas que l'optimisation prématurée est diabolique ? Si on recherche l'optimisation, on verra bien lors des tests les fonctions qui posent réellement problème.
    Ce n'est certes pas un problème de performances, c'est un problème de compréhension de l'utilisateur...

    L'utilisateur, quel qu'il soit (moi en premier, sans doute) est un imbécile distrait qui va tirer un tas de conclusions basées sur les noms des fonctions qu'il rencontre.

    Je n'oserais pas essayer de compter le nombre de fois où, en phase de débug, je me suis dit "telle fonction est sensée faire ceci, je pars du principe qu'elle le fait correctement" pour me rendre compte, deux heures après, que j'aurais beaucoup mieux fait de rentrer directement voir ce que faisait la fonction car elle mentait sur ce qu'elle faisait en en faisant plus que ce qu'elle ne disait.
    Je trouve ton exemple pas très parlant.
    "Déplacer" un objet n'a pas la même signification que de le poser à un endroit donné.
    On peut très bien avoir des méthode move et des méthodes setPosition dans une même classe.
    Avec move, on effectue un "déplacement", un mouvement.
    Avec setPosition, on lui assigne une position, il n'y a pas vraiment de "mouvement".
    Mais, si tu as plusieurs fonctions, move aura un sens particulier qui indique le déplacement et setPosition serait avantageusement renommé en enlageFromTopLeft qui indique clairement ce qui est fait (et qui donne alors cette notion du fait que le bounding box a de grandes chances d'être modifié )
    P.S. On dérive un peu du sujet originel, ne devrions-nous pas déplacer ce débat dans un autre sujet?
    Je m'en occupe dés que j'ai posté ma réponse
    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

  14. #14
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    cette manière est dépréciée au profit de nothrow (la seule spécification restante est le fait qu'une fonction s'engage éventuellement à ne pas lancer d'exception )
    C'est un peu HS mais ceci signifie que pour chaque méthode on est obligé d'aller voir la doc pour connaître toutes les exceptions qu'elle pourrait lancer (?)

    Citation Envoyé par koala01 Voir le message
    Méfies toi de ce qui est "évident", ca ne l'est jamais autant que ce que l'on pourrait imaginer
    Tu marques un point^^

    Citation Envoyé par koala01 Voir le message
    Je pars du principe que l'utilisateur d'une classe n'a pas à aller voir le code qui se cache derrière une fonction pour pouvoir l'utiliser.

    Et je pars du principe que l'utilisateur n'ira pas voir la doc s'il croit avoir saisi le but poursuivi par une fonction, sur base de son nom.

    Je présumes que tu ne pourras pas faire autrement que d'être d'accord avec moi sur ces deux principes, non
    Je ne peux être que d'accord en effet^^

    Citation Envoyé par koala01 Voir le message
    Mais, pour qu'il puisse ne pas avoir à s'inquiéter de ce genre de chose, il faut que les comportements que l'on met à sa disposition au travers de l'interface publique d'une classe soient suffisamment explicites pour ne laisser aucune ambiguïté quant au résultat qu'il obtiendra en les invoquant
    Mais si la méthode se contente de laisser l'objet dans un état cohérent sans plus, j'ai un peu du mal de comprendre ce qui n'irait pas. En effet l'utilisateur s’attend toujours à ce que l'objet reste dans un état cohérent non? Je pense donc que l'utilisateur s'attende à ce que tout ce qui est lié à la propriété modifié soit modifié (si nécessaire) pour rester cohérent.
    Exemple : je déplace un objet, tous les objets "enfants" de cet objet seront eux aussi déplacé de manière absolut mais leur position relative restera inchangée.


    Citation Envoyé par koala01 Voir le message
    Je ne dis pas qu'il faut interdire les choses pouvant mener à des abus, je dis qu'il est de notre devoir de faire en sorte que l'utilisateur puisse utiliser ce qu'on lui fourni sans avoir à se poser de question... La nuance est de taille, non
    En gros faire un code le plus intuitif possible. Mais il faut reconnaître que c'est très loin d'être simple dans certains cas.


    Citation Envoyé par koala01 Voir le message
    Si tu choisi correctement le nom de tes comportements plutôt que de céder à la facilité qui consiste à choisir un nom "générique"
    Mais les noms génériques ne permettent-ils pas d'être retrouver très rapidement grâce à l'intuition et à l'auto-complétion?
    Ce qui rendrait la classe plus simple à utiliser (?)
    Citation Envoyé par koala01 Voir le message
    Cela n'a rien à voir...

    L'invalidation des itérateur est la conséquence logique du concept mis en oeuvre par le conteneur envisagé
    Mais cela reste source d'erreur car pas forcément évident pour tout le monde (?)

    D'ailleurs je comprend mal pourquoi aucune bibliothèque (à ma connaissance) ne respectent pas ces principes pourtant ceux qui les codent sont loin d'être des débutants (?)
    Par exemple, pour la SFML 1.6 combien de fois ai-je dû regarder les sources pour comprendre pourquoi la fonction ne marchait pas comme je l'aurais pensé ?
    <troll>Ou alors Qt4.7 qui nous ment quand même pas mal et qui est très loin d'être intuitive.</troll>
    Sans compter qu'à ma connaissance toutes les bibliothèques on des méthodes "set" comme setEnable().

    Mais nommer ces fonctions/méthodes de façon à être sûr que les utilisateurs comprennent exactement ce qu'elle fait est très difficile si on ne veut pas faire des noms à rallonge (changePositionAndUpdateBoxingAndMakeCoffee()) est très difficile, ne serait-ce pas un peu "idyllique" pour certains cas ? Peut-on vraiment se permettre de passer 2 semaine à chercher le meilleurs nom pour une méthode ?
    <troll level=gbd*****>Ne vaudrait-il pas mieux nommer les fonctions de manière à ce qu'on soit sûr que l'utilisateur ne comprennent pas ce qu'elle fait afin de l'inciter à lire la doc et ainsi éviter les erreur? </troll>

    En conclusion, je pense que le principal problème c'est de trouver les bons noms qui pourraient remplacer les "set" et qui dans certains cas peut être vraiment compliqué...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    C'est un peu HS mais ceci signifie que pour chaque méthode on est obligé d'aller voir la doc pour connaître toutes les exceptions qu'elle pourrait lancer (?)
    C'est en effet plutôt HS, mais l'explication allant dans le sens de ma thèse, autant en profiter

    En fait, c'est la prise en compte d'un problème bien plus complexe que le simple fait de devoir aller voir la doc...

    Le fait est que, pour une fonction "simple" (comme un accesseur tout ce qu'il y a de plus basique), il serait effectivement facile de s'assurer qu'il ne renvoie qu'une ou deux exceptions en cas de besoin (un out_of_range quelconque pour une fonction at, par exemple), mais que, pour les fonctions un peu plus complexes (il suffit qu'elles fassent appel à new, de manière directe ou indirecte !!!), ca devient tout de suite beaucoup plus compliqué.

    En effet, il "suffit" qu'une des fonctions appelées de manière directe ou indirecte lance une exception non récupérée par les différentes fonctions appelées de manière directe ou indirecte qui n'apparaisse pas dans la spécification des exceptions que tu donnes pour ta fonction pour que le programme s'arrête sur une "unexpected exception".

    Tu ne peux donc pas te contenter de spécifier les seules exceptions qui seront lancées par ta fonction en elle-même, mais tu dois veiller à spécifier toutes les exceptions (non gérées au niveau de ta fonction) qui pourraient être lancées par les fonctions appelées (de manière directe ou indirecte) par ta fonction.

    Cela t'oblige pour ainsi dire à savoir exactement quelles fonctions sont appelées, à quelles conditions, quelles exceptions elles risquent de lancer et dans quelles conditions.

    Ce n'est pas vraiment l'idée que l'on peut se faire de l'encapsulation hein

    Mais c'est aussi la raison pour laquelle il faut veiller à indiquer des noms "auto documentés" à tes fonctions.

    Quand je lis une fonction setXXX, je me dis que cette fonction... défini une valeur à celle que je vais lui transmettre, ni plus, ni moins.

    Si le mutateur est remplacé par un comportement clairement défini, qui ne modifie peut etre que partiellement un objet complexe (exemple : une font), je me poserai d'autres questions en fonction du nom du comportement (tiens, est ce que moveTo déplace l'objet "instantanément" )

    Mais si la méthode se contente de laisser l'objet dans un état cohérent sans plus, j'ai un peu du mal de comprendre ce qui n'irait pas. En effet l'utilisateur s’attend toujours à ce que l'objet reste dans un état cohérent non? Je pense donc que l'utilisateur s'attende à ce que tout ce qui est lié à la propriété modifié soit modifié (si nécessaire) pour rester cohérent.
    Exemple : je déplace un objet, tous les objets "enfants" de cet objet seront eux aussi déplacé de manière absolut mais leur position relative restera inchangée.
    Mais l'utilisateur a-t-il seulement la moindre idée de ce qu'est l'état cohérent de son objet

    Comment veux tu que l'utilisateur (car il faut se mettre du point de vue de l'utilisateur, et tu sais tout le bien que je pense de lui ) d'un objet puisse savoir qu'une fonction va veiller à garder l'objet dans un état cohérent s'il ne sait même pas à quoi correspond cet état cohérent, et comment veux tu qu'il puisse imaginer une seconde que la fonction fait autre chose que simplement définir "quelque chose" à la valeur qu'il indique si la fonction ne lui indique pas clairement ce qu'elle fait
    En gros faire un code le plus intuitif possible. Mais il faut reconnaître que c'est très loin d'être simple dans certains cas.
    Et qui a dit que l'informatique était simple

    Le boulot d'un développeur est de se casser la tête pour que les autres n'aient plus à le faire après lui

    Mais les noms génériques ne permettent-ils pas d'être retrouver très rapidement grâce à l'intuition et à l'auto-complétion?
    Je ne crois sincèrement pas...

    Qu'est ce qui est plus intuitif selon toi
    SetPosition, sans savoir si "le coin opposé suivra" ou "moveTo" et enlargeTopLeft

    Quant à l'auto-complétion, elle ne pourra jamais proposer l'un pour l'autre, donc, quoi qu'il en soit, elle suivra l'intuition de l'utilisateur
    Ce qui rendrait la classe plus simple à utiliser (?)
    En quoi

    L'auto complétion est une possibilité donnée par un outil qui a pour but d'éviter à l'utilisateur de taper trop de lettres, mais ca se limite là...

    Ce qui rend une classe "simple à utiliser", c'est autre chose, à commencer par le fait qu'elle soit "bien conçue"
    Mais cela reste source d'erreur car pas forcément évident pour tout le monde (?)
    On peut prendre le problème dans un autre sens : en quoi l'auto-complétion sera-t-elle plus utile si tu te trouve avec dix ou quinze propositions après avoir écrit "get" (ou "set") que si tu te trouves avec deux possibilités (move et moveTo) après avoir écrit "mov"
    [EDIT]Ouppss... tu parlais de l'invalidation des itérateurs...

    Ce problème vient surtout du fait que les gens n'ont sans doute pas compris le concept du conteneur qu'ils utilisent ni le fait qu'il ne faut jamais préjuger que quelque chose est valide après avoir effectuer un accès en écriture sur un conteneur

    Je t'accorde le fait que cela peut poser problème
    [/EDIT]
    D'ailleurs je comprend mal pourquoi aucune bibliothèque (à ma connaissance) ne respectent pas ces principes pourtant ceux qui les codent sont loin d'être des débutants (?)
    Parce qu'ils oublient demeter
    Par exemple, pour la SFML 1.6 combien de fois ai-je dû regarder les sources pour comprendre pourquoi la fonction ne marchait pas comme je l'aurais pensé ?
    <troll>Ou alors Qt4.7 qui nous ment quand même pas mal et qui est très loin d'être intuitive.</troll>
    Le développement de Qt a, pour son malheur, été lancé à une période à laquelle on était moins attentif à cela

    Elle subit son le poids de son histoire et de sa base de code, comme tout le monde
    Sans compter qu'à ma connaissance toutes les bibliothèques on des méthodes "set" comme setEnable().
    Est-ce une raison pour continuer en ce sens

    Qu'est ce qui t'interdit de commencer à avoir une fonction enable() et une autre disable() dans ton propre développement pour les remplacer

    Tu gagnerais sur tous les tableaux
    Mais nommer ces fonctions/méthodes de façon à être sûr que les utilisateurs comprennent exactement ce qu'elle fait est très difficile si on ne veut pas faire des noms à rallonge (changePositionAndUpdateBoxingAndMakeCoffee())
    Si c'est le nom qui représente ce que fait la fonction, autant l'utiliser
    est très difficile, ne serait-ce pas un peu "idyllique" pour certains cas ? Peut-on vraiment se permettre de passer 2 semaine à chercher le meilleurs nom pour une méthode ?
    Je ne parle pas de passer deux semaine à chercher le meilleur nom de fonction, il s'agit de prendre cinq minutes pour en trouver un meilleur que setXXX
    En conclusion, je pense que le principal problème c'est de trouver les bons noms qui pourraient remplacer les "set" et qui dans certains cas peut être vraiment compliqué...
    Peut être, parfois...

    Mais beaucoup moins si déjà tu respecte SRP, et moins encore si tu envisage le fait de travailler "en miroir" (une fonction qui fait, une qui défait )
    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

  16. #16
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Si le mutateur est remplacé par un comportement clairement défini, qui ne modifie peut etre que partiellement un objet complexe (exemple : une font), je me poserai d'autres questions en fonction du nom du comportement (tiens, est ce que moveTo déplace l'objet "instantanément" )
    En fait il faudrait que l'utilisateur n'utilise pas une nouvelle méthode avant d'avoir lu la doc (?)

    Citation Envoyé par koala01 Voir le message
    Qu'est ce qui est plus intuitif selon toi
    SetPosition, sans savoir si "le coin opposé suivra" ou "moveTo" et enlargeTopLeft
    "le coin opposé suivra" ie ?
    enlargeTopLeft ne me semble pas approprié pour désigner un changement de position, ne signifie-t-il pas "agrandir" ? Or ce n'est pas le but d'un setPosition

    Citation Envoyé par koala01 Voir le message
    donc, quoi qu'il en soit, elle suivra l'intuition de l'utilisateur En quoi

    L'auto complétion est une possibilité donnée par un outil qui a pour but d'éviter à l'utilisateur de taper trop de lettres, mais ca se limite là...
    Dans Qt4.7, je trouve pratique de taper par exemple "is"/"to"/... pour réduire la liste des méthodes où je vais rechercher celle qui m'intéressent.


    Citation Envoyé par koala01 Voir le message
    Ce qui rend une classe "simple à utiliser", c'est autre chose, à commencer par le fait qu'elle soit "bien conçue" On peut prendre le problème dans un autre sens : en quoi l'auto-complétion sera-t-elle plus utile si tu te trouve avec dix ou quinze propositions après avoir écrit "get" (ou "set") que si tu te trouves avec deux possibilités (move et moveTo) après avoir écrit "mov"
    move reste assez fréquent mais je pense par exemple à itemFromIndex() où là il faut souvent parcourir plusieur fois toute la liste des méthode pour la trouver mais aussi pour la retrouver.


    Citation Envoyé par koala01 Voir le message
    Est-ce une raison pour continuer en ce sens
    Bien sûr que non mais le fait qu'elles n'appliquent pas ces principes nous fait un peu douter, nous prive de bons exemples et nous habitue à "l'inverse".


    Citation Envoyé par koala01 Voir le message
    Qu'est ce qui t'interdit de commencer à avoir une fonction enable() et une autre disable() dans ton propre développement pour les remplacer
    Pour enable et disable, l'intérêt est un peu limité de faire un setEnable(bool) mais on peut faire des petits trucs du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    bool b;
    while(1)
    {
       C.setEnable(b);
        b = !b;
    }
    Si on a un setter pouvant prendre 20 valeurs (ou plus), je ne pense pas qu'il soit judicieux de le remplacer par 20 méthodes (?)

    Sinon, cela semble surtout être une question d'habitude et de préjugé, on a l'habitude que le set ne fasse qu'une affectation.
    Mais si on commence à remplacer des setSize() par des changeSize() et que cela devient très fréquent, est-ce qu'appeler une méthode changeSize() ne pourrait pas devenir aussi "sale" qu'un setSize() parce qu'on aura alors l'habitude que changeSize() fasse "ceci" mais pas autre chose ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    En fait il faudrait que l'utilisateur n'utilise pas une nouvelle méthode avant d'avoir lu la doc (?)
    Non (quoi que...) l'idée est qhaque nouvelle fonction indique clairement ce qu'elle fait
    "le coin opposé suivra" ie ?
    je veux dire par là que la taille de mon objet ne sera pas modifiée...

    Essayes de suivre un peu la conversation
    enlargeTopLeft ne me semble pas approprié pour désigner un changement de position, ne signifie-t-il pas "agrandir" ?
    Si, justement, c'est pour cela que j'ai fait le parallèle entre move(To) + enlargeTopLeft d'un coté et setPostion de l'autre
    Or ce n'est pas le but d'un setPosition
    Le problème est, justement, que l'on ne sait pas à quoi s'attenre avec setPostion...

    Déplace-t-elle l'objet ou peut etre en modifie-t-elle la taille Si elle ne le retourne pas

    La seule solution pour le savoir passe par la doc ou par le code, et tu viens de me donner raison quand je dis que l'utilisateur n'ira pas voir le premier et n'a pas à aller voir le second
    Dans Qt4.7, je trouve pratique de taper par exemple "is"/"to"/... pour réduire la liste des méthodes où je vais rechercher celle qui m'intéressent.
    Tu peux le faire avec n'importe quel autre nom

    move reste assez fréquent mais je pense par exemple à itemFromIndex() où là il faut souvent parcourir plusieur fois toute la liste des méthode pour la trouver mais aussi pour la retrouver.
    Soit celui qui a besoin de cette fonction la connait, soit il l'aura trouvée dans la doc (en se posant la question de comment faire ) ... A partir de là, l'auto-complétion fera le reste


    Bien sûr que non mais le fait qu'elles n'appliquent pas ces principes nous fait un peu douter, nous prive de bons exemples et nous habitue à "l'inverse".
    Ah, enfin un point sur lequel je suis d'accord
    Pour enable et disable, l'intérêt est un peu limité de faire un setEnable(bool) mais on peut faire des petits trucs du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    bool b;
    while(1)
    {
       C.setEnable(b);
        b = !b;
    }
    Sauf que ca oblige l'utilisateur à savoir quel est l'état d'origine pour initialiser b.

    Or, le plus souvent, tu vas surtout avoir une logique qui déterminera si ton objet doit etre actif, indépendamment de l'état dans lequel il se trouve ou non
    Si on a un setter pouvant prendre 20 valeurs (ou plus), je ne pense pas qu'il soit judicieux de le remplacer par 20 méthodes (?)
    Pourquoi pas

    Prenons l'exemple d'une font...

    Si tu as une fonction setFont, tu dois récupérer la font en question, puis, que peux tu faire avec
    Changer sa taille
    1. changer la font (passer de arial à windings)
    2. la faire passer en gras (ou en non gras)
    3. la faire passer en italique (ou non)
    4. la faire passer en souligné (ou non)
    5. la faire passer en barré (ou non)
    6. changer sa taille
    7. sans doute une ou deux chose encore
    Tout cela implique que tu dois avoir la connaissance de la classe font pour le faire...

    Or, la grosse majorité de l'usage que tu en feras sera de modifier une partie de ces informations à chaque fois (la faire passer de gras à non gras, modifier la taille, ou que sais-je)

    Pourquoi devrais tu avoir une telle connaissance de la classe Font alors que tu devrais pouvoir te contenter de dire "je veux l'afficher en gras" ou "je veux utiliser windings"

    Sinon, cela semble surtout être une question d'habitude et de préjugé, on a l'habitude que le set ne fasse qu'une affectation.
    C'est bien le problème auquel on est confronté quand il ne fait pas que l'affectation
    Mais si on commence à remplacer des setSize() par des changeSize() et que cela devient très fréquent, est-ce qu'appeler une méthode changeSize() ne pourrait pas devenir aussi "sale" qu'un setSize() parce qu'on aura alors l'habitude que changeSize() fasse "ceci" mais pas autre chose ?
    Beaucoup moins...

    Parce que setSize n'est sensé faire que ca, alors que changeSize (ou mieux resize ) ne prétend pas ne faire que cela: il passe le message qui est qu'il peut faire autre chose que simplement modifier un membre de la classe.

    D'ailleurs, il pourrait très bien modifier deux membres, voir effectuer des vérifications, le terme laisse le choix

    Et si l'utilisateur se pose la question de savoir ce qui se passe réellement lors d'un resize, il ira voir la doc (ou le code ) pour en avoir le coeur net.

    Chose qu'il ne fera d'office pas avec setSize parce que, pour lui, setSize ne fait que changer la taille
    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

  18. #18
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Pour moi enlargeTopLeft ça veut dire agrandir par le coin d'en haut à gauche sans toucher au coin en bas à droite...

  19. #19
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Déplace-t-elle l'objet ou peut etre en modifie-t-elle la taille Si elle ne le retourne pas
    Je ne vois pas pourquoi un setPosition modifierait la taille de l'objet.


    Citation Envoyé par koala01 Voir le message
    Sauf que ca oblige l'utilisateur à savoir quel est l'état d'origine pour initialiser b.
    Pas nécessairement, il peut faire un setEnabled(true) sur un objet déjà activé.


    Citation Envoyé par koala01 Voir le message
    Prenons l'exemple d'une font...

    Si tu as une fonction setFont, tu dois récupérer la font en question, puis, que peux tu faire avec
    Changer sa taille
    1. changer la font (passer de arial à windings)
    2. la faire passer en gras (ou en non gras)
    3. la faire passer en italique (ou non)
    4. la faire passer en souligné (ou non)
    5. la faire passer en barré (ou non)
    6. changer sa taille
    7. sans doute une ou deux chose encore
    Tout cela implique que tu dois avoir la connaissance de la classe font pour le faire...

    Or, la grosse majorité de l'usage que tu en feras sera de modifier une partie de ces informations à chaque fois (la faire passer de gras à non gras, modifier la taille, ou que sais-je)

    Pourquoi devrais tu avoir une telle connaissance de la classe Font alors que tu devrais pouvoir te contenter de dire "je veux l'afficher en gras" ou "je veux utiliser windings"
    Mais dans ce cas là pour changer la taille, la font (Times new Roman, ...) on pourrait utiliser des "set" (?)


    Citation Envoyé par koala01 Voir le message
    Parce que setSize n'est sensé faire que ca
    Est-il vraiment censé faire que ça? La définition de "set" ne dit que c'est un "changement vers un état défini" ce qui peut impliquer d'autres opérations. Ne serait-ce pas plutôt parce qu'on pense (à tord) qu'il serait censé faire que cela ?

    Citation Envoyé par koala01 Voir le message
    alors que changeSize (ou mieux resize ) ne prétend pas ne faire que cela: il passe le message qui est qu'il peut faire autre chose que simplement modifier un membre de la classe.

    D'ailleurs, il pourrait très bien modifier deux membres, voir effectuer des vérifications, le terme laisse le choix

    Et si l'utilisateur se pose la question de savoir ce qui se passe réellement lors d'un resize, il ira voir la doc (ou le code ) pour en avoir le coeur net.

    Chose qu'il ne fera d'office pas avec setSize parce que, pour lui, setSize ne fait que changer la taille
    Le problème c'est que si un jour, changeSize() devient répandu, on sera confronté au même problème qu'avec setSize(), des personnes penseront qu'elle ne peut faire qu'une seule chose et n'iront pas voir la documentation.

    Dès lors ne peut-on pas considérer le fait de ne pas aller voir la doc quelque soit la fonction/méthode comme une erreur aussi grave que de faire un cast_const à tout va ?
    Nous ne serions alors pas responsable des erreurs que ferait un programmeur qui ne lirait pas la doc comme nous ne sommes pas responsable si un utilisateur s'amuse avec cast_const ?
    Car c'est bien d'essayer de faire un code le plus intuitif et le plus "idiot-proof" mais en C++, dès qu'on veut faire une bêtise, rien ne peut nous en empêcher.
    Par exemple rien ne m'empêche de récupérer l'adresse d'un objet stocké dans un container et de faire un delete dessus.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Concernant resize...

    En fait, si l'on remplace setSize(tailleX, tailleY) par resize(tailleX, tailleY), il n'y a, effectivement, aucun avantage

    Ce qu'il faut faire, pour être cohérent, c'est une fonction resize(differenceX, differenceY)

    En effet, si l'utilisateur doit s'inquiéter de récupérer la taille actuelle de l'objet pour pouvoir déterminer la nouvelle taille (que ce soit pour setSize ou pour la première version de resize ), on donne, encore une fois, une responsabilité à l'utilisateur qu'il ne devrait pas avoir : celle de déterminer la taille de l'objet redimensionné.

    C'est faire un pari assez osé que de se dire que l'utilisateur pensera au fait que l'objet subit des contraintes de tailles et qu'il pensera à les vérifier (en plus, s'il y pense, ca fait encore augmenter sa responsabilité et le risque de voir de la duplication de code).

    Par contre, si on envisage la fonction resize selon la deuxième version (celle qui prend deux différences de taille ), on libère l'utilisateur de ces obligations dans le sens où l'on peut parfaitement faire en sorte qu'elle vérifiera d'elle-même les contraintes de taille (ca fait partie de ce que l'on attend du comportement de redimensionnement, non ) et dans le sens où l'utilisateur n'a plus à s'inquiéter de la valeur effective de la taille, mais bien "d'avoir une taille suffisante pour ce qui l'intéresse".

    Et du coup, toute la "popote interne" qui consiste à vérifier les contraintes, à calculer la nouvelle taille etc se retrouve correctement encapsulée dans une fonction dont c'est le but avéré
    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

Discussions similaires

  1. fonctions et classes... quand les utiliser ?
    Par fastmanu dans le forum Langage
    Réponses: 6
    Dernier message: 03/04/2006, 00h39
  2. Quand les tableaux deviènent vos pires enemis...
    Par Zenol dans le forum Balisage (X)HTML et validation W3C
    Réponses: 10
    Dernier message: 13/11/2005, 21h23
  3. Outils pour creer les accesseurs et les mutateurs
    Par MarieMtl dans le forum MFC
    Réponses: 3
    Dernier message: 03/10/2005, 17h03

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