Journal Ⓒ✙✙ Le tiret bas (underscore) au début des variables membres ?

11
18
août
2018

En réponse à guppy, j’ai rédigé un long commentaire qui mérite d’être promu en journal.   \_o_/

La norme C++ réserve l’utilisation du tiret bas (underscore)

Résumé de la norme Ⓒ✙✙ : https://en.cppreference.com/w/cpp/language/identifiers

[…]

An identifier can be used to name objects, references, functions, enumerators, types, class members, namespaces, templates, template specializations, parameter packs, goto labels, and other entities, with the following exceptions:

  • the identifiers that are keywords cannot be used for other purposes;
  • the identifiers with a double underscore anywhere are reserved;
  • the identifiers that begin with an underscore followed by an uppercase letter are reserved;
  • the identifiers that begin with an underscore are reserved in the global namespace.

[…]

Reformulons + exemples

On reformule différemment :

  1. Éviter le tiret bas au début ;

    #ifndef _MA_CLASSE_H   // Non, on a dit pas au début
    #define _MA_CLASSE_H
    ...
    #endif
    
    #ifndef MA_CLASSE_H_   // Oui, autorisé à la fin
    #define MA_CLASSE_H_
    ...
    #endif
  2. Éviter deux tirets bas consécutifs n’importe où ;

    #ifndef MA_CLASSE__H   // Non, pas de double tiret bas au milieu
    #define MA_CLASSE__H
    ...
    #endif
    
    #ifndef MA_CLASSE_H__  // Non, pas à la fin non plus
    #define MA_CLASSE_H__
    ...
    #endif
  3. Exception du tiret bas au début.
    Autorisé dans une portée locale (local scope) et suivi par une minuscule (ou un chiffre…).

    #ifndef MA_CLASSE_H   // Oui
    #define MA_CLASSE_H
    
    class _MaClasse       // Non
    {
      const double _PI = 3.14; // Non
      int _MonEntier = 0;      // Non
      int _monEntier = 0;      // Oui
      int __monEntier = 0;     // Non
      int _mon_entier = 0;     // Oui
      int _mon__entier = 0;    // Non
      int _0_0_ = 0;           // Oui
      int _ = 0;               // Oui
      int _Fonction();         // Non
      int _fonction();         // Oui
    };
    
    int _fonction();           // Non
    
    int fonction (int _a) {    // Oui
      int _ = _a;              // Oui
      return _;
    }
    
    #endif

Règle simple

On simplifie la règle pour la retenir :

  1. Jamais deux tirets bas consécutifs n’importe où ;
  2. Le tiret bas au début réservé aux _variablesMembres.

Car le tiret bas pour les variables membres à des avantages.
Mais ceux qui ne sont pas d’accord pourraient plutôt adopter cette règle :

  1. Jamais deux tirets bas consécutifs ;
  2. Jamais le tiret bas au début.

Avantages du tiret bas au début

  1. Quand seules les variables commencent par un tiret bas, l’auto-complétion distingue les fonctions des variables. Lors de l’activation de l’auto-complétion, tout est listé, mais d’abord les fonctions sans être pollué par les variables. Et si on cherche le nom d’une variable, il suffit d’entrer un tiret bas. Attention à éviter les variables membres avec une majuscule en second caractère car c’est potentiellement un mot réservé.

  2. Un second avantage, plus esthétique, est l’alignement des tiret bas lors de la déclaration des variables membres. C’est difficilement le cas avec le tiret bas final.

Exemples issus des GreatPractices C++ rules :

struct Limit
{
  int32_t quantity;
  double  price;
  bool    isActive;
};

class MyClass
{
public:
  double volume() const;
private:
  int32_t _quantity;
  double  _price;
  bool    _isActive;
};

double MyClass::volume() const
{
  volume = _price * _quantity
  return volume;
}

Quand utiliser le tiret du bas ?

Si une struct (ou une class) expose ses variables en public et ne possède pas (ou peu) de fonctions, alors pas besoin de distinguer les variables des fonctions (pas d’intérêt à utiliser les tirets du bas).

Par contre, si une class (ou une struct) expose des fonctions en public et le reste est private, alors distinguer les nombreuses fonctions des nombreuses variables est intéressant (variables membres préfixées par le tiret du bas pour les variables s’applique).

Bien entendu, une class ou struct qui a pour destinée de ne posséder que peu de fonctions et variables, alors pas besoin d’artifice pour distinguer les fonctions des variables, le tiret du bas n’est pas obligatoire.

Règle simple :

  1. Choisir struct quand ce sont essentiellement des variables public, et donc ne pas utiliser le tiret du bas ;
  2. Dans les autres cas, choisir plutôt class et préfixer les variables membres avec un tiret bas ;
  3. Déroger à la règle dans les autres cas (trait, …).

Voir aussi

  • # Je ne veux pas passer pour un emmerdeur ...

    Posté par . Évalué à 10 (+12/-4).

    … mais Ⓒ✙✙ c'est vraiment très très moche dans un titre. Au passage, je suppose que c'est pas génial pour nos amis mal/non voyants. Quoiqu'il en soit, "le C++, c'est pour les dinos !".

    • [^] # Re: Je ne veux pas passer pour un emmerdeur ...

      Posté par (page perso) . Évalué à 2 (+1/-1).

      Oui, le C++ est langage vieux d'une quarantaine d'années, forcément il y a plein de dinos dans son écosystème.

      Mais pas seulement, plein de jeunes apprécient le C++, j’en côtoie tous les jours.

      Tu peux t’en rendre compte en visionnant des vidéos sur le sujet :

      ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺ ☻ ☺

      C’est à la fois, un langage du passé et un langage d’avenir.
      On ne code plus en C++ aujourd’hui comme il y a 10 ans. Le langage n’est pas mort, mais au contraire, le C++ évolue énormément actuellement, voir mes deux commentaires sur la dépêche Faut-il continuer à apprendre le C++ ?.

      Le C++ n’est plus du C avec des trucs en +.
      Le C++ est devenu un langage à part entière, avec même des incompatibilités avec les dernières versions du C.
      D’ailleurs, pour apprendre le C++, je déconseille de passer par le C, mais aller directement vers le C++ avec, par exemple, les C++ Core Guidelines.

      Personnellement, j’utilise d’autres langages selon les situations, et c’est ça le plus intéressant : le choix dans la diversité des langages de programmation.

      Et donc, je NE te conseille PAS d’apprendre le C++ car aujourd’hui d’autres langages aussi intéressants (voir même plus) sont bien plus faciles à apprendre.


      Au fait, es-tu malvoyant ?
      Sais-tu comment Ⓒ✙✙ est prononcé dans un titre de journal ?

      Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)

      • [^] # Re: Je ne veux pas passer pour un emmerdeur ...

        Posté par . Évalué à 5 (+3/-0).

        Au fait, es-tu malvoyant ?
        Pas encore, mais j'en côtoie quelques uns. J'en connais un en particulier qui boude à chaque fois qu'un chef de projet "créatif" remplace un A par un @ dans le nom de son projet.

        Sais-tu comment Ⓒ✙✙ est prononcé dans un titre de journal ?
        Dans le meilleur des cas, c'est sauté et donc pour ce titre en particulier, ça manque alors sérieusement de contexte.

        En règle générale, c'est un bon exercice de se poser la question de l'accessibilité, même pour un petit journal sur linuxfr ou une petite appli web. J'ai déjà vu une appli interne qui affichait en vert pas trop foncé sur fond vert clair …

        Concernant le C++, je trouve certains aspects de sa syntaxe (ou de ses conventions) plutôt moches mais ce n'est pas très grave puisque j'ai "passé l'âge de coder" et je ne suis plus obligé d'en lire.

        • [^] # Re: Je ne veux pas passer pour un emmerdeur ...

          Posté par (page perso) . Évalué à 2 (+1/-1).

          Merci pour l’info. Je compte activer les outils d’accessibilité pour vérifier mon prochain texte. Je renseigne déjà les alt pour les images et fournissant une description complète. Je ne sais pas si un mal-voyant a pu bénéficier de cela…

          Pour éviter d’invisibiliser le genre féminin, je fais déjà un effort pour utiliser des mots épicènes sans toutefois avoir recours à l’écriture inclusive qui ne plaît pas forcément au lectorat de LinuxFr.org. Rédiger devient de plus en plus compliqué quand on cherche à respecter toutes les contraintes !

          Pour la syntaxe C++ capillotractée, les développeurs sont les premiers à s’en plaindre !

          Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)

      • [^] # Re: Je ne veux pas passer pour un emmerdeur ...

        Posté par . Évalué à 1 (+2/-2).

        C’est à la fois, un langage du passé et un langage d’avenir.

        Comme le Fortran ou le COBOL.

        ok -> []

  • # Pourquoi un tiret bas?

    Posté par (page perso) . Évalué à -1 (+1/-4).

    Chez moi, les variables membres sont préfixées par un f (comme "field"), les statiques par un s, et les constantes par un k. Et les méthodes ont des noms qui commencent par une majuscule, donc pas de conflit possible lors de la complétion.

        struct Limit
        {
            int32_t fQuantity;
            double  fPrice;
            bool    fActive;
        };
    
    
        class MyClass
        {
             public:
                 double  Volume() const;
    
             private:
                 int32_t fQuantity;
                 double  fPrice;
                 bool    fAsActive;
    
                 static const double kTaxes;
        };
    
    
        double MyClass::Volume() const
        {
             double volume = fPrice * fQuantity * (1 + kTaxes);
             return volume;
        }
    

    Et puis franchement, y'a vraiment pas beaucoup de caractères réservés dans les noms des identifiers, pourquoi vouloir justement utiliser ceux-là? Pourquoi pas un ‿ par exemple?

    • [^] # Re: Pourquoi un tiret bas?

      Posté par (page perso) . Évalué à 3 (+1/-0).

      Je pense qu'avec un peu d’entraînement, ta règle des préfixes f, s et k peut augmenter ton confort et donc ta productivité.

      Par contre, quand de nombreux intervenants accèdent au code source, la lisibilité/compréhension du code devient plus importante, et donc la bonne pratique et d'éviter les règles qui changent la prononciation des variables comme fActive. C'est par exemple le cas des projets libres qui souhaitent accueillir de nouveaux contributeurs, ou des codes sources communs à plusieurs équipes dans une entreprise.

      Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)

      • [^] # Re: Pourquoi un tiret bas?

        Posté par (page perso) . Évalué à 10 (+9/-0).

        Je recommande la lecture (complète) de https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ et le passage sur l'infameuse "hungarian notation". Je ne recommande à personne de préfixer des variables selon le type, la portée, ou n'importe quelle autre raison qui ne soit pas la sémantique pure du code et de ce qu'il fait. De la même façon, utiliser le tiret du bas en préfixe est relativement stupide: un bon éditeur saura faire du surlignage de différentes couleurs selon la portée de la variable, et proposer une autocomplétion de code intelligente qui met en premier les variables dont la portée est la plus proche.

        • [^] # Re: Pourquoi un tiret bas?

          Posté par . Évalué à 5 (+3/-0). Dernière modification le 19/08/18 à 23:00.

          Pour être tout à fait honnête, préfixer avec de simples lettres est pas très malin non plus, même quand c’est purement semantique.
          Pour reprendre l’exemple de spolsky, une meilleure convention serait “préfixer les variables non safe avec ‘unsafe’, ne pas préfixer les autres”, ce qui:

          • met l’accent sur le fait qu’on ne veut pas de variables non échappées dans le code, en tout cas le moins possible.
          • rend le code lisible. Je veux pas dire, mais s ou us, ça me parle pas. Et préfixer chaque putain de variable rend le code assez illisible, sans compter que la différence entre s et us est assez maigre quand même.
          • accessoirement, en tout cas dans cet exemple, utiliser un framework un tant soit peu decent qui échappe les chaînes par défaut, et ne pas utiliser des pratiques de 1997 qui sont connues pour faire de la merde (a savoir, concatèner des chaînes à droites à gauches, et faire du token replacement qui va rendre ton code vachement plus simple à lire)

          En gros, l’idee C’est de désigner le bouzin pour rendre ce genre d’erreurs impossible/très dure a écrire en premier lieu. La notation hongroise, ça revient à se reposer sur de la discipline pour éviter un bug qui ne devrait pas être possible en premier lieu, ce qui est pas franchement très malin.

          Pour les variables membres, 2 choses:

          • si l’autocompletion marche mal, utilise une autre auto complétion. On en 2018, les ide arrivent généralement à savoir ce que tu veux en fonction du contexte
          • this/self c’est pas fait pour les chiens. Oui, ca fait 5 characters de plus a taper, mais ca evite les erreurs. Ça serait appreciable si les compilos pouvaient émettre un warning quand une variable locale masque un membre cela dit (il me semble que les ide java peuvent facilement être configuré pour émettre un warning quand un membre n’est pas préfixe par this/self)

          Linuxfr, le portail francais du logiciel libre et du neo nazisme.

          • [^] # Re: Pourquoi un tiret bas?

            Posté par . Évalué à 3 (+2/-1). Dernière modification le 19/08/18 à 23:50.

            En gros, l’idee c’est de désigner le bouzin pour rendre ce genre d’erreurs impossible/très dure a écrire en premier lieu.

            Oui, et c'est ce qui m'a le plus choqué dans l'article : utiliser des conventions syntaxiques sur les noms de variables et non le système de types pour porter des informations sémantiques. Un code non propre ne devrait même pas compiler !

            Pour faire court :

            • les types sont des concepts dont on construit les objets ;
            • les chaînes de caractères se subdivisent en deux catégories : les sures et les autres ;
            • on définit un sous-type pour représenter les chaînes sures ;
            • la fonction write ne doit accepter que des chaînes sures en entrée, sinon le code refuse de compiler.

            Grossièrement, une spécification simplifiée de son problème dans la syntaxe de mon langage de prédilection ressemble à ceci :

            val request : field -> string
            
            module type Safe = sig
              type t = private string
              val encode : string -> t
              val write : t -> unit
            end

            J'ose espérer que l'auteur n'est pas responsable de système critique sur le plan de la sécurité ou il vaudrait mieux qu'il retourne fabriquer du pain industriel : il n'y a rien de plus sale et moins propre que ce qu'il préconise. ;-)

            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

            • [^] # Re: Pourquoi un tiret bas?

              Posté par . Évalué à 2 (+0/-0).

              Spolsky a des défauts, mais les langages qu'il utilise sont ceux de son industrie (il fait des trucs Web, donc il faut penser PHP, JavaScript, ASP, .Net, etc.).

              J'aime bien le typage statique, mais ça n'empêche pas qu'il existe des cas compliqués ou à la marge. Par exemple : programmation parallèle en mémoire partagée. C'est pour ça que j'aime préfixer mes variables quand elles sortent du contexte « normal » qu'on s'attend à trouver. Par exemple :

              #include <pthread.h>
              #include <stdio.h>
              #include <stdint.h>
              
              #define N 100ul
              
              volatile int g_COUNTER;
              
              typedef struct { 
                  int id;
              } id_t;
              
              void* worker(void* arg) {
                  id_t id = (id_t*) arg;
              /*  Façon très mauvaise de créer une section critique dans le cas général */
                  while (g_COUNTER != id->id)
                      ; //nothing
                  ++g_COUNTER;
              
                  return 0;
              }
              
              int main(void)
              {
                  pthread_t threads[N];
                  id_t      ids[N];
                  for (size_t i = 0; i < N; ++i) {
                      ids[i].id = N-i-1;
                      if (0 != pthread_create(threads+i, NULL, worker, ids+i))
                          abort(); // pour faire simple
                  }
              
                  for (size_t i = 0; i < N; ++i)
                      if (0 != pthread_wait(threads[i], NULL))
                          abort(); // pour faire simple
              
                  printf("counter = %d\n", g_COUNTER);
              }

              Dans ce contexte, presque tout suit une convention de nommage classique, mais mes macros sont écrites en majuscules pour bien montrer qu'on parle de constantes (N), et pour mes variables globales, je préfixe par g_ ET je mets en majuscules, parce que dans un contexte multi-threadé, on ne met jamais trop d'avertissements dans le nom de la variable pour qu'on se souvienne qu'il faut faire attention ⇒ g_COUNTER.

        • [^] # Re: Pourquoi un tiret bas?

          Posté par . Évalué à 1 (+3/-3).

          Le monsieur a son avis, et ce n'est que son avis.

          Perso la notation hongroise j'adore. Je passe énormément de temps à relire du code et c'est incroyablement utile quand tu peux voir un code qui n'est pas familier et vite voir ce qui est global, local, membre de la classe, voir la taille des entiers et pouvoir évaluer si il y a un overflow possible…

          Ensuite, cette notation je baigne dedans depuis longtemps donc j'ai l'habitude, mais je suis aussi beaucoup moins confortable quand je dois lire du code sans ces marques, cela me prend bien plus de temps pour avoir les infos dont j'ai besoin car elles ne sont pas à portée d'yeux.

          • [^] # Re: Pourquoi un tiret bas?

            Posté par . Évalué à 3 (+3/-1).

            Perso je n'aime pas du tout. C'est une surcharge cognitive qui va encore ajouter des caractères augmentant la taille des lignes pour une info que mon éditeur est tout à fait en mesure de me restituer via la couleur. Et oui si on me passe un snipet de code je vais le mettre dans mon éditeur pour le lire. Je ne lis pas les pdf avec cat, mais un lecteur pdf. C'est pareil pour le code.

            C'est pareil d'ailleurs pour les INomDeClass et les NomDeClassImpl.

            • [^] # Re: Pourquoi un tiret bas?

              Posté par (page perso) . Évalué à 5 (+4/-1).

              Christie Poutrelle dit :

              […] un bon éditeur saura faire du surlignage de différentes couleurs selon la portée de la variable […]

              Barmic dit :

              […] une info que mon éditeur est tout à fait en mesure de me restituer via la couleur.

              Je sais que c'est un débat sans fin mais je demande juste pour comparer nos méthodes, sans vouloir militer :

              Comment vous en sortez vous quand vous devez lire du code hors de l'éditeur ?

              Perso je me retrouve régulièrement à lire du code un peu partout : un bête terminal, parfois en remote sur un serveur peu equipé, un navigateur web (GitHub, UpSource), dans un courriel, sur mon téléphone… Je ne peux pas toujours compter sur une coloration sémantique.

              • [^] # Re: Pourquoi un tiret bas?

                Posté par . Évalué à 5 (+4/-0).

                Comment vous en sortez vous quand vous devez lire du code hors de l'éditeur ?

                barmic dit :

                Et oui si on me passe un snippet de code je vais le mettre dans mon éditeur pour le lire. Je ne lis pas les pdf avec cat, mais un lecteur pdf. C'est pareil pour le code.

                J'utilise mon éditeur préféré. Tout le temps. S'il peut m'arriver de lire du code hors, il faut vraiment qu'il soit trivial.

                C'est une habitude à prendre, mais sincèrement, j'ai autant besoin de savoir qu'un identifiant représente un champ non statique mutable que de savoir que c'est un tableau ou un vecteur par exemple. Je suis donc vraiment trop limité quand je ne suis pas dans un éditeur adapté. Du fait que, je n'ai pas les helpers (des tooltips qui te montrent la déclaration par exemple) ni la navigation dans les sources. Si je n'ai pas besoin de ça, alors le code est suffisamment concis pour ne pas avoir besoin d'ajouter des bidouilles aux identifiants pour les comprendre.

                Et en soit ça va très vite. Je n'ai aucune difficulté à prendre un bout de code et à l'ouvrir avec mon éditeur, ça ne représente pas de gros overhead. Pour upsource, que j'utilise aussi, mon intellij a un plugin vraiment pratique et je n'ouvre plus l'interface web.

                Je trouve aussi que le fait d'être dans un environnement habituel permet de plus facilement y passer du temps. Quand tu regarde du code avec ed à travers une connexion série depuis un serveur au milieu de la zone interdite de Tchernobyl, tu va être moins enclins à approfondir ta lecture.

              • [^] # Re: Pourquoi un tiret bas?

                Posté par (page perso) . Évalué à 6 (+6/-1). Dernière modification le 21/08/18 à 14:05.

                Comment vous en sortez vous quand vous devez lire du code hors de l'éditeur ?

                D'où l'importance d'expliciter les this ou self, ce qui enlève toute ambiguïté à la lecture, et de plus rend aussi la lecture naturelle, car le fait que les membres soient des membres est alors à la fois explicite et dans l'ordre de lecture.

                D'où l'importance de donner des noms qui soit sémantiquement liés à ce que fait et à quoi sert réellement le membre ou la variable, comme ça, plus d’ambiguïté du tout. Joel Spolsky a tout à fait raison de ce point de vue là: peu importe les normes de nommages, peu importe le langage: une personne qui ne connaît ni l'un ni l'autre doit comprendre ce que le code fait.

                De toute évidence, lire du code sans un bon éditeur n'est que faire une revue très partielle de ce dernier, impossible d'aller en profondeur sans utiliser un outil qui en donne une (de profondeur) par la navigation dans le code, la navigation cyclique dans les références, et les avertissements sémantiques tel que la non utilisation d'une variable ou la détection de code mort, et toute ces autres informations utiles que seule la lecture ne peut pas donner.

            • [^] # Re: Pourquoi un tiret bas?

              Posté par . Évalué à 1 (+0/-0).

              Les couleurs n'aident pas.

              Ta variable qui est membre de la classe, et un entier 32bits signé a quelle couleur ?

              La variable qui est locale à la fonction et un entier 16bits non signé a quelle couleur ?

              • [^] # Re: Pourquoi un tiret bas?

                Posté par . Évalué à 5 (+4/-0).

                Je compare à la notation hongroise, mais justement tu met quoi dans tes identifiants :

                • leur type ? est-ce que c'est un entier ? le quel ? virgule flottante double ou pas ? un tableau ? un vecteur ? une liste chaînée ? une instance de ta classe A ? une lambda/fonction qui prends 1, 2 ou 3 paramètres ? Les paramètres c'est des références ? des copies ? ils peuvent être null ? ils ont des valeurs par défaut ?…
                • son scope ? local, global, dans une fonction, un paramètre de ta méthode, un champ hérité de ta classe ?
                • s'il est static ? si c'est une constante ? s'il est volatile ?
                • s'il est partagé entre des threads, tu fais quelque chose ?
                • s'il est thread safe tu as un marqueur pour le dire ?
                • s'il a une chance d'être null ou pas tu le marque comment ?

                Si tu encode tout ça dans tes identifiants, d'une part tu essaie de réécrire ton système de type, mais en plus tu va totalement surcharger ton algo. Le seul qui peut me donner toutes ces informations c'est mon éditeur. Que tu fasse le choix de présenter certaines informations plutôt que d'autres dans la liste non exhaustive que j'ai donné est un choix subjectif qui n'a rien de global. Tu as des contexte où on se fout de connaître la porté, mais savoir ce qui est volatile ou pas est critique.

                • [^] # Re: Pourquoi un tiret bas?

                  Posté par . Évalué à 1 (+2/-2).

                  m_dwX -> membre de la classe, unsigned 4-bytes integer
                  m_iX -> membre de la classe, signed 4-bytes integer
                  g_wX -> variable globale, unsigned 2-bytes integer
                  m_sX -> stl string, 1 byte par caractere
                  m_wsX -> stl string, 2 bytes par caractere
                  m_oX -> objet quelconque membre de la classe
                  m_spoX -> shared pointer d'un objet quelconque membre de la classe
                  etc…

                  Il faut évidemment se limiter, perso j'ai le scope et les types courants.

                  • [^] # Re: Pourquoi un tiret bas?

                    Posté par . Évalué à 4 (+3/-0).

                    Perso je préfère y mettre la sémantique, parce que c'est la seule chose que mon éditeur ne peux pas me présenter.

                  • [^] # Re: Pourquoi un tiret bas?

                    Posté par (page perso) . Évalué à 5 (+5/-1).

                    ça ressemble au mauvais usage de la notation hongroise, Joel Spolsky à fait un super article la dessus il y a un paquet d'années: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/

                    I’m using the word kind on purpose, there, because Simonyi mistakenly used the word type in his paper,
                    and generations of programmers misunderstood what he meant.

                    • [^] # Re: Pourquoi un tiret bas?

                      Posté par (page perso) . Évalué à 6 (+5/-1). Dernière modification le 20/08/18 à 16:36.

                      On tourne en rond, quelqu'un a déjà donné ce lien.

                      La réponse reste la même: ce genre d'infos devrait être encodé dans le type de la variable, pas dans son nom. Pour reprendre l'exemple du blog, il faudrait une classe UnsafeString, et les chaînes non sûres devraient être stockées dans des variables de ce type.

                      Après, on peut, au choix, mettre un operator= (ou un opérateur de cast, ou…) qui va faire la conversion de façon transparente (mais il faut bien réfléchir), ou ajouter la méthode .Encode() pour que ce soit explicite.

                      Et du coup, ce n'est plus au développeur de vérifier ce genre de choses: le compilateur va faire le job tout seul. Le mauvais code fonctionnera quand même dans le premier cas (on va juste perdre en performance avec des conversions inutiles de partout), et ne compilera même pas dans le second.

                      Par contre, et c'est ce dont on débat ici, il n'est pas question d'avoir un type différent pour une variable locale et un membre d'une classe. Donc, dans ce cas, avoir un préfixe peut faire sense (encore que, utiliser systématiquement this-> n'est pas forcément une mauvaise idée, quoi qu'un peu verbeuse).

                      • [^] # Re: Pourquoi un tiret bas?

                        Posté par . Évalué à 2 (+4/-3).

                        Mais ça c'est la belle théorie, en pratique tout le monde fait des opérations entre entiers signés / non signé de différentes tailles, personne ne s'amuse à créer une infrastructure pour faire cela sûrement avec des types propres car c'est très contextuel et ancré dans les habitudes.

                        Et quand tu revois ce code pour y trouver des failles et autres, les infos de la notation hongroise sont extrêmement utiles.

                        Je passes plus de temps à lire le code des autres qu'à en écrire et vraiment, la notation hongroise aide. Je suis bien plus efficace sur ce genre de code que sur le code sans cette notation.

                        • [^] # Re: Pourquoi un tiret bas?

                          Posté par . Évalué à 3 (+2/-0).

                          Je passes plus de temps à lire le code des autres qu'à en écrire et vraiment, la notation hongroise aide. Je suis bien plus efficace sur ce genre de code que sur le code sans cette notation.

                          On appelle ça l'habitude, je te sors de ta nomenclature et tu va beaucoup moins aimer. Si tu as à trouver un bug qui nécessite de s'intéresser à autre chose que ce que tu encode dans tes identifiants et ça va tout de suite être moins drôle. Tu semble être particulièrement attaché aux overflow en arithmétique, mais ce n'est qu'une classe de bug parmi d'autres (en plus elle se détecte très facilement).

              • [^] # Re: Pourquoi un tiret bas?

                Posté par (page perso) . Évalué à 3 (+3/-2).

                Rien ne t'empêche d'avoir une couleur différente pour chaque caractère du nom de ta variable, avec une signification différente.

                Mais pour moi, du code propre et bien rédigé doit pouvoir se lire sans coloration syntaxique. La coloration, c'est pratique pour essayer de démêler un code illisible.

                • [^] # Re: Pourquoi un tiret bas?

                  Posté par . Évalué à 2 (+1/-0).

                  Mais pour moi, du code propre et bien rédigé doit pouvoir se lire sans coloration syntaxique.

                  Je suis un peu d'accord, mais je dirais la même chose pour tout ce que l'on cherche à encoder dans les identifiants.

                  La recherche de la simplicité devrait réduire fortement la charge cognitive et donc limiter le nombre de variables manipulées, le nombre de variable mutée, le nombre de scopes parcourus, la taille du code,…

                  Mais il reste les cas de code très technique qui sont moins là pour la propreté de l'algo que comme boilerplate autour des techno que tu utilise par exemple.

                  La coloration, c'est pratique pour essayer de démêler un code illisible.

                  Donc tu peux t'en passer si tu n'a aucune dette technique et si toutes les pull requests sont parfaites à la première revue :)

              • [^] # Re: Pourquoi un tiret bas?

                Posté par . Évalué à 6 (+5/-0).

                Ton éditeur te le signal quand il y a des problèmes de cast, je déteste cette notation hongroise qui sert vraiment à rien (comme l'underscore en début de variables privées), à part alourdir la lecture.

                Mon cerveau met plus de temps à la décoder qu'a retrouver la déclaration. Et c'est très moche.

  • # Pareil

    Posté par . Évalué à 4 (+3/-1).

    Salaire oblige, je code en java, et j'ai adopté la même règle de _ en début de variable membre, et franchement ça améliore grandement la lisibilité - même si les éditeurs peuvent utiliser un couleurs différentes pour celles-ci.

    De plus ça permet d'éviter les conflits avec les arguments des méthodes : pas la peine de préfixer avec this, pas de collisions possibles en cas de renommages.

    Bref, le plus dur c'est de convaincre les autres d'adopter cette convention, mais ça c'est un combat sans fin (comme la position des {}, la taille des indentations, etc…)

    • [^] # Re: Pareil

      Posté par (page perso) . Évalué à 5 (+4/-0). Dernière modification le 19/08/18 à 18:01.

      Je suis contre les préfixes avec _ (cf. mon commentaire d'au dessus). Ceci dit, excellent point, les éditeurs savent mettre en valeur les variables en fonction de leur portée ou de leur origine, et c'est ça le bon outil à utiliser!

      De plus, le conflit de nom avec les paramètres, c'est pas tous les jours, et dans le cas où ça arrive, utiliser le this. pour désambiguer est à la fois légitime, et probablement plus explicite pour le lecteur.

      • [^] # Re: Pareil

        Posté par . Évalué à 0 (+2/-2).

        De plus, le conflit de nom avec les paramètres, c'est pas tous les jours, et dans le cas où ça arrive, utiliser le this. pour désambiguer est à la fois légitime, et probablement plus explicite pour le lecteur.

        Ce qui m'arrive le plus souvent c'est les conflits entre membre et accesseur, et là, le this-> ne résout rien. Il faut donc un préfixe/suffixe soit pour le membre, soit pour l'accesseur (e.g. utiliser get_membre). Je préfère garder un joli nom pour l'accesseur et mettre un préfixe à mon membre privé.

      • [^] # Re: Pareil

        Posté par . Évalué à 3 (+3/-2). Dernière modification le 20/08/18 à 18:08.

        Exemple de conflit : le setter.

        int value;
        public setValue(int value) {…

        Là il faut this.value, ou nommer autrement le parametre, mais on perd en expressivité.

        Alors qu'avec int _value, plus de soucis.

        Et il y a plein de cas ou on utilise un nom de variable membre simple, qui peut être source de conflit avec un argument d'une méthode : "name", "type", "value", "enabled", etc.
        On peut bien sûr utiliser des noms style objectName, trucType, etc, mais c'est plus long a taper, et je suis fainéant.

        • [^] # Re: Pareil

          Posté par . Évalué à 3 (+4/-2).

          Là il faut this.value, ou nommer autrement le parametre, mais on perd en expressivité.

          Devoir faire ça pour des getters, setters ou accesseurs c'est tout de même dommage. C'est les trucs les plus triviaux possible (on parle d'une ligne ou d'une affectation) que dans une bonne partie des cas on génère. Teinter tout son code pour ça je trouve ça vraiment dommage…

          Et il y a plein de cas ou on utilise un nom de variable membre simple, qui peut être source de conflit avec un argument d'une méthode : "name", "type", "value", "enabled", etc.

          Ça m'arrive et généralement c'est qu'il y a quelque chose de mal nommé. Si tu as un champ de ta classe qui s'appelle name, c'est bizarre qu'il possède une méthode foo(std::string name) mais qui ne représente pas la même chose. C'est probablement que l'un des 2 pourrait être nommé de manière plus clair (par exemple en explicitant de quoi est-il le nom).

  • # et m_ par rapport à juste _?

    Posté par . Évalué à 5 (+4/-0).

    et quid de m_val par rapport à val
    m pour member
    c'est quoi le plus utilisé m
    ou juste le _ ?

    • [^] # Re: et m_ par rapport à juste _?

      Posté par (page perso) . Évalué à 3 (+3/-0).

      Qt utilise (dans les exemples et leur code) le m_ pour les variables privées. Le getter est le nom de la variable, le setter : setNom. Les booleans sont différencés avec un isBoolName().

      Le tout c'est d'être cohérent partout.

    • [^] # Re: et m_ par rapport à juste _?

      Posté par (page perso) . Évalué à 4 (+2/-0). Dernière modification le 20/08/18 à 02:48.

      La notation hongroise était très à la mode dans les années 1990-2000. Des entreprises, comme Microsoft, usaient de cette notation dans leurs exemples (les bonnes pratiques). Il faut dire qu’à l’époque Intel+MSWindows était en train de remplacer SPARC+Solaris. Seule une minorité travaillait sur d’autres systèmes que MS-Windows.

      Cette notation hongroise recommandait, entres autres, les préfixes suivants:

      1. m_ variable membre
      2. g_ variable globale
      3. s_ variable statique
      4. l_ variable locale

      Les deux premiers préfixes m_ et g_ sont restés longtemps perdurent bien que la notation hongroise ne soit plus utilisée (des personnes dans mon entourage continuent de les utiliser).

      Supposons que les variables globales soient tellement rares de nos jours que nous pouvons négliger le préfixe g_.
      La question :
      Au final, quel est l’intérêt de garder le m (dans m_) si on n’utilise plus les autres préfixes ?

      Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)

      • [^] # Re: et m_ par rapport à juste _?

        Posté par . Évalué à 7 (+6/-0).

        Voir la différence entre une variable locale à la méthode et les membres de la classe est toujours utile.

        • [^] # Re: et m_ par rapport à juste _?

          Posté par . Évalué à 0 (+0/-2).

          Je plussoie, dans mon travail on avait comme règle de codage que les membres commençaient par m_ puis ça a changé on ne devait plus utilisé m_ (merci Oncle Bob!) .. 15j plus tard j'ai perdu ~2h a ne pas trouver un bug d'une collègue qu'elle n'aurait pas faite si on avait gardé l'ancienne règle de codage (ou qui m'aurait crevé les yeux si elle avait fait l'erreur quand même)
          --> perso: fuck, la nouvelle règle de codage (et oui, on a gardé la nouvelle règle même quand j'ai rapporté le problème).

          • [^] # Re: et m_ par rapport à juste _?

            Posté par . Évalué à 2 (+1/-0).

            --> perso: fuck, la nouvelle règle de codage (et oui, on a gardé la nouvelle règle même quand j'ai rapporté le problème).

            Et tu as le droit de merger ? Perso que les règles de codage me plaisent ou non je les respecte et je refuse les revues qui ne les respecte pas. On peut discuter de ce qui est mieux ou pas (comme ici), mais chacun y va de sa propre règle, alors ça perturbe totalement les relectures (on ne sais pas ce que signifie l'absence de m_). Perso même si je considère que c'est pas particulièrement une bonne pratique, je m'y plierais sans rechigner si mon équipe considère qu'elle préfère travailler comme ça.

  • # this->

    Posté par (page perso) . Évalué à 3 (+2/-0).

    Je les préfixe avec this->

    C’est plus simple.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.