Journal C++ vin va vous faire tourner en barrique !

Posté par  (site Web personnel) . Licence CC By‑SA.
Étiquettes :
19
17
sept.
2020

Ah Nal,

Je viens de découvrir avec grand plaisir que C++, mon premier amour de langage, va enfin entrer dans le vingtième siècle en adoptant un système de modules similaire à ce que l'on trouve dans les autres langages.

Ces modules seront introduit dans C++20:

Exemple d'un module dans un fichier duck.cpp:

export module duck;
import <iostream>;

export void quack() {
    std::cout << "Coin coin !" << std::endl;
}

Son utilisation:

import duck;

int main() {
    quack();
}

Il y a aussi d'autres nouveautés intéressantes (coroutines, concepts…), mais je ne les attendais pas autant que ces modules qui mettent enfin C++ au niveau de Pascal !

  • # Quel est l'intérêt ?

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

    Je ne pratique pas du tout le C++ et je ne comprends pas le concept de modules, qu'est-ce que cela apporte ? Quel en est l'intérêt ? Je déclare ma fonction dans un header qui est inclus dans mon .c(pp) et ça fait la même chose, non ? Qu'est-ce que j'ai raté ?

    Accessoirement, je remarque que si on incrémente C : C++ = D et qu'on retire C++ (donc D) du mot "module", on obtient "moule".

    • [^] # Re: Quel est l'intérêt ?

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

      Le problème des headers est qu'ils sont interprétés des tonnes de fois. Même avec des gardes, c'est lu et relu pour chaque unité de compilation les utilisant. Sur des gros projets ou de grosses dépendances ça se sent.

      De plus le résultat de l'interprétation peut varier d'une unité de compilation à l'autre selon les paramètres du préprocesseur.

      // header.hpp
      #pragma once
      
      #ifdef FOO
        using bar = int;
      #else
        using bar = char;
      #endif
      
      // 1.cpp
      #include "header.hpp"
      
      static_assert(std::is_same_v<bar, char>)
      
      // 2.cpp
      #define FOO // ou -DFOO sur la ligne de commande
      #include "header.hpp"
      
      static_assert(std::is_same_v<bar, char>)
      // Perdu, bar est int.

      Les modules sont une réponse à ces problèmes.

      • [^] # Re: Quel est l'intérêt ?

        Posté par  (site Web personnel) . Évalué à 2 (+4/-4). Dernière modification le 17/09/20 à 13:41.

        hum, pour ça on peut juste s'interdire les #ifdef dans un .h, et la solution apportée pose la question de comment on fait le même comportement sans les includes (si le ifdef est dans le .h, c'est pour une raison… Perso je l'utilise par exemple suivant si l'utilisateur veut une version Unicode ou pas de ma lib, utile à une époque même si moins de nos jours, je ne vois pas comment proposer ça simplement avec les modules, à part faire comme Java par avoir les 2 interfaces pour tous et limiter la taille du bousin est un truc que j'aime en C++ justement).

        J'espère qu'il y aura de meilleurs arguments :p, et surtout une aide à la transition en expliqaunt comment faire "moderne" avec tous les cas d'usage d'avant (en espérant ne pas se prendre "ha ben ça c'est pas moderne, on a viré du moderne t'es trop un nul à vouloir x d'avant").

        PS : bouh du code non standard :p. (oui je sais tous les compilos l'acceptent, juste pour taquiner)

        • [^] # Re: Quel est l'intérêt ?

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

          Perso je l'utilise par exemple suivant si l'utilisateur veut une version Unicode ou pas de ma lib, utile à une époque même si moins de nos jours, je ne vois pas comment proposer ça simplement avec les modules, à part faire comme Java par avoir les 2 interfaces pour tous et limiter la taille du bousin est un truc que j'aime en C++ justement).

          Si j'ai bien compris, tu as toujours le droit d'utiliser des #ifdef, mais les defines sont limités au module qui en a besoin. Plus besoin d'ajouter un -DZENITRAM_UNICODE pour la compilation de tous les fichiers qui pourraient inclure directement ou indirectement tes headers. Le revers c'est que les modules ne peuvent plus exporter de macros.

          • [^] # Re: Quel est l'intérêt ?

            Posté par  (site Web personnel) . Évalué à 3 (+3/-2). Dernière modification le 17/09/20 à 14:12.

            Reprenons, exemple générique :

            #ifdef FOO
              using bar = int;
            #else
              using bar = char;
            #endif
            // Ici une longue API dépendante de bar

            il y a 2 version de la lib sans le source fourni à l'utilisateur, une avec FOO et une sans, actuellement 1 seul .h.
            Mon exemple peut être stupide mais on peut en trouver plein d'autres légitimes (nouvelle version avec ABI qui casse etc)
            Comment faire la même chose avec les modules?

            PS : je n'ai fait que survoler les modules pour le moment, donc tolérance SVP sur mon non connaissance de la chose, et c'est surtout pas contre les modules, à la base je trouve l'idée sympa et me rappelle une époque très lointaine où je faisais du dev Java avec ce genre de limitation frustrante :p.

            • [^] # Re: Quel est l'intérêt ?

              Posté par  (site Web personnel) . Évalué à 5 (+3/-1).

              Si tu as du code qui varie selon le type, il vaut mieux utiliser des templates que des macros, non?

              Incubez l'excellence sur https://linuxfr.org/board/

              • [^] # Re: Quel est l'intérêt ?

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

                Ça dépend… si tu veux exposer ta lib au monde entier, il te faut une API C-style, chose qu'a ma connaissance seuls 2 langages permettent de faire facilement: le C, forcément, et le C++.

                Il faudrait ne pas oublier qu'il s'agit d'un élément important pour certaines personnes (dont moi).
                Les macro, c'est comme goto en fait: ça dois être utilisé le moins possible, mais parfois c'est juste ce qu'il y a de mieux (plus souvent pour les macros que pour goto clairement).

                • [^] # Re: Quel est l'intérêt ?

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

                  Oui mais c'est hors-sujet. Les entêtes de ton API C-style n'ont le droit d'utiliser aucun idiome du C++. Donc le mélange de directives du préprocesseur et des macro ne se pose pas dans ce cas d'utilisation là.

            • [^] # Re: Quel est l'intérêt ?

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

              En quoi les modules vont changer ce genre de hack crade?
              Ton #ifdef il va s'appliquer au module, et il va exporter ton api avec bar aliasant int ou char en fonction du #ifdef. Ton module doit toujours etre compilé a l'avance, avec les bonnes options.
              La grosse différence c'est que tu peux plus casser ton build en important le mauvais header au mauvais endroit, ni te demander s'il faut utiliser < ou ". tu fais juste import NomDeLaLib

              Et tout a fait entre nous, si ta justification anti module c'est que ca rend plus dur de faire du polymorphisme a coup de #ifdef, heu ben voila quoi. Utilise une configuration runtime, utilise des templates, je sais pas, fait qq chose, mais traiter les type comme du texte, ca va te peter a la gueule un jour.
              Vu les commentaires que tu as fait récemment sur les Linuxiens qui refusent de se remettre en question sur le DE, je suis convaincu que tu vas immédiatement te remettre en cause, d'ailleurs?

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

              • [^] # Re: Quel est l'intérêt ?

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

                Pardon, j'ai mal lu.
                Un seul header, 2 librairies, tu cherches les problèmes.

                J'ai pas suivi les details des modules C++, mais au pire du pire, tu te retrouves avec 2 headers differents, chacun étant "compile" pour le #ifdef spécifique.
                Le code de tes clients va peter s'ils linkent la mauvaise librairie, mais ca c'est une feature, pas un bug. C'est une des raisons pour laquelle faire de la compilation conditionnelles de features est une mauvaise idée.
                Expose une configuration runtime, ou utilise de la genericite (template je suppose dans ton cas) pour l'api. Ta librairie sera un peu plus grosse, mais vu ton domaine, je suis pas sur que ca soit un reel probleme.

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

              • [^] # Re: Quel est l'intérêt ?

                Posté par  (site Web personnel) . Évalué à -3 (+4/-9).

                J'ai pas suivi les details des modules C++, mais au pire du pire, tu te retrouves avec 2 headers differents […] C'est une des raisons pour laquelle faire de la compilation conditionnelles de features est une mauvaise idée.

                Justement, le préprocesseur est autant adulé pour permettre des bidouilles que détesté car il permet trop de bidouilles mais ce n'est pas avec un "au pire" que ça se répond…

                je suis convaincu que tu vas immédiatement te remettre en cause

                Ton plaisir d'animosité personnelle a déjà été plus pertinent, ici difficile que je me remette en cause puisque je n'ai pas spécialement d'avis et même que je trouves les modules très bien sur l'idée (à moins que tu voulais que je me remette en cause pour ne pas les aimer? Tarabiscoté).
                "anti module" est une notion que tu as inventé (basé sur? ma réaction "J'espère qu'il y aura de meilleurs arguments :p"? euh…) pour le plaisir, sortir un truc HS sur les DE en montre tout la petitesse.

                Mais peut-être qu'à la base il est juste dommage d'avoir comme plaisir de l'animosité personnelle…

              • [^] # Re: Quel est l'intérêt ?

                Posté par  (site Web personnel) . Évalué à 1 (+2/-3). Dernière modification le 17/09/20 à 20:07.

                (doublon, ça rame)

              • [^] # Re: Quel est l'intérêt ?

                Posté par  . Évalué à 5 (+3/-0). Dernière modification le 17/09/20 à 21:10.

                Exemple pris de LMDB (ok, pas du C++, mais l’idée y est) :

                #ifdef _MSC_VER
                typedef int mdb_mode_t;
                #else
                typedef mode_t  mdb_mode_t;
                #endif

                ou encore :

                /** An abstraction for a file handle.
                 *  On POSIX systems file handles are small integers. On Windows
                 *  they're opaque pointers.
                 */
                #ifdef _WIN32
                typedef void *mdb_filehandle_t;
                #else
                typedef int mdb_filehandle_t;
                #endif

                Du coup je suis pas bien sur de comprendre. Tu peux toujours faire ça avec les nouveaux modules C++, ou ça va pêter ?

                • [^] # Re: Quel est l'intérêt ?

                  Posté par  (site Web personnel) . Évalué à 3 (+1/-0). Dernière modification le 18/09/20 à 06:17.

                  Oui tu peux toujours faire ça.
                  C'est juste que la macro _WIN doit être définie (ou pas) lors de la compilation du module. Et ça ne peux plus changer quand le module est utilisé.

            • [^] # Re: Quel est l'intérêt ?

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

              Comment faire la même chose avec les modules?

              Maintenant que j'ai un peu lu. Tu n'a plus d'intérêt d'avoir le header. Tu peux le garder et les builds ne changeront pas, mais tu ne distribue plus les headers.

              Donc il n'y aura plus d'erreur possible entre les options que tu as choisi pour ta bibliothèque et celles utilisées par ton utilisateur.

              J'ai conscience de répéter des choses déjà dites, mais en pédagogie paraphraser pour changer la manière de présenter peut être utile.

              Évidemment avant que des bibliothèques partagées passent à ça (et posent comme contraintes C++20 minimum), il y aura du temps.

        • [^] # Re: Quel est l'intérêt ?

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

          si le ifdef est dans le .h, c'est pour une raison…

          La plus courante, c’est quand-même de ne pas tout péter quand ton .h est lui même inclus par un autre .h. Le #ifdef ressemble alors plus à un contournement malheureux qu’à une solution justifiée par une bonne raison. Dans l’exemple que tu donnes, tu peux bien mettre le #ifdef dans la déclaration du module, et il sera appliqué une bonne fois pour toutes, au lieu d’être redécouvert à chaque nouveau fichier .c(pp) qui utilise ton .h.

          Personnellement, l’absence de module est l’une des principales choses qui me rend la programmation en C++ désagréable, les autres problème que j’avais avec ce langage s’étant bien améliorés avec C++17. Tant mieux si en 2020, C++ devient un langage aussi moderne que Fortran.

      • [^] # Re: Quel est l'intérêt ?

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

        Il y a une réponse StackOverflow qui a l'air pas mal intéressante sur le sujet.

      • [^] # Re: Quel est l'intérêt ?

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

        Le problème des headers est qu'ils sont interprétés des tonnes de fois. Même avec des gardes, c'est lu et relu pour chaque unité de compilation les utilisant.

        D'où les non-standards headers précompilés, oui.

        Je suis curieux, comme zenitram: le but est vraiment "juste" l'accélération de la compilation?
        Personnellement, j'en suis venu à ne pas mettre de directives de précompilation dans mes headers, ni même d'y utiliser des namespaces.
        Oui, ça implique que chaque source qui les inclue doive faire le boulot, mais la compilation est rapide et en cadeau bonus il est aisément possible de passer d'une lib à une autre: il suffit de mettre "using std::vector;" ou "using foo::vector;" avant l'include.
        Bien sûr, ça a ses inconvénients, mais aussi des avantages, notamment pour de petits codes sources.
        J'ai un petit outil pour lequel l'usage de mon propre vector divise par 2 la taille du binaire, notamment. J'ai pas fait de mesure pour les autres métriques (temps d'exécution moyen et consommation en ram) cela dis. Et je parle de vector ici, du conteneur le plus simple.

        Je pense l'avoir déjà dis, mais peut-être que le problème de vitesse de compilation de C++, c'est juste que les gens font de la merde, à tout inclure comme des porcs sans réfléchir?

        Aussi, je me pose la question de la simplicité (trompeuse) de communication avec le C, qui (malgré qu'elle soit trompeuse) est un des avantages du C++.

        Tout ça ne veux ni dire que je suis contre les modules, ni dire qu'ils n'ont aucun intérêt (je ne suis pas sûr de l'intérêt, et qu'ils soient la ou non m'indiffère pour l'instant).

        • [^] # Re: Quel est l'intérêt ?

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

          Je pense l'avoir déjà dis, mais peut-être que le problème de vitesse de compilation de C++, c'est juste que les gens font de la merde, à tout inclure comme des porcs sans réfléchir?

          Qu'est-ce qui te fait croire ça ? ;)

        • [^] # Re: Quel est l'intérêt ?

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

          D'où les non-standards headers précompilés, oui.

          Ça reste non-standards. C'est plus du domaine du hack que de la solution.

          Si j'en crois ce que j'ai lu, les modules suppriment la séparation header/implémentation. Avant que tu vienne du C bibliothèques tout ça tout ça. Les modules ne déprécient pas les headers, tu peux toujours continuer à faire tes bibliothèques pour C ou C++ de la même façon. Mais le C++ ne sert pas qu'à créer des bibliothèques et des projets comme LibreOffice seront content de pouvoir réduire leur temps de builds.

          La suppression de la séparation header/implémentation permet aussi d'éviter le DRY et d'avoir à maintenir en double chaque changements.

          Un autre point que j'ai lu c'est que les macro ne sortent pas des modules, c'est aussi un effet de bord qui peut être pratique.

          Encore une fois c'est des trucs qui peuvent ne pas vous être utile, mais c'est pas pour autant que c'est inutile.

          • [^] # Re: Quel est l'intérêt ?

            Posté par  . Évalué à 2 (+0/-0). Dernière modification le 19/09/20 à 01:06.

            c'est pas pour autant que c'est inutile.

            . (oui, faut vraiment mettre un truc sinon ça fait une seule citation)

            Tout ça ne veux ni dire que je suis contre les modules, ni dire qu'ils n'ont aucun intérêt (je ne suis pas sûr de l'intérêt, et qu'ils soient la ou non m'indiffère pour l'instant).

            ;)

            • [^] # Re: Quel est l'intérêt ?

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

              Pour aller plus loin, tu ne va pas distribuer tes headers précompilés. Là où avec les modules ça ne pose pas de problème.

        • [^] # Re: Quel est l'intérêt ?

          Posté par  (site Web personnel) . Évalué à 4 (+1/-0).

          Oui, ça implique que chaque source qui les inclue doive faire le boulot, mais la compilation est rapide et en cadeau bonus il est aisément possible de passer d'une lib à une autre: il suffit de mettre "using std::vector;" ou "using foo::vector;" avant l'include.

          Si ta lib accepte plusieurs implémentations d'un vecteur qui respecte le même contrat, pourquoi ne pas faire du policy based design ?

          L'usage serait ainsi plus propre.

          #include <malib>
          
          malib::maclasse<std::vector> c;
          
          c.faire_des_trucs_avec_des_vecteurs();
          

          Incubez l'excellence sur https://linuxfr.org/board/

    • [^] # Re: Quel est l'intérêt ?

      Posté par  (site Web personnel) . Évalué à 6 (+4/-0).

      je remarque que si on incrémente C : C++ = D et qu'on retire C++ (donc D) du mot "module", on obtient "moule".

      Une blague connexe : C++, ça augmente le C, mais ça renvoie toujours du C.

  • # #les-blagues-fines

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

    Ah Nal,

  • # similaire à Java ?

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

    Un truc cool dans java et les packages c'est qu'il est facile d'avoir des classes qui sont visible que par le package, est-ce que le mot clef module permet ca ?

Envoyer un commentaire

Suivre le flux des commentaires

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