À propos de cppcon 2020

Quelques raccourcis :

Notez que le contenu de cette page est en chantier, en particulier sur le plan du formatage, car je suis débordé. Je retravaillerai le tout dès que possible, promis.

Grâce à l'Université de Sherbrooke (en particulier, grâce à Jean Goulet et à Claude Cardinal du CeFTI) et au Collège Lionel-Groulx (en particulier à Éric St-Jean, à Patrick Lebonnois, à Lucia Lepage et à mes collègues du département d'informatique), j'ai le privilège de participer (virtuellement, étant donné la pandémie de COVID-19 qui sévit) à CppCon 2020.

Ce qui suit est une sorte de journal de voyage (sans la partie voyage!), avec éléments humains et éléments techniques. Au besoin, référez-vous à ce glossaire : ../../Lexique/lexique-wg21.html

Notez que j'ai eu une semaine très, très occupée, et que j'ai assurément oublié de mentionner plusieurs rencontres. Si je ne vous ai pas mentionné, ça en dit plus sur ma mémoire défaillante que sur l'intérêt que je vous ai porté.

Pour un peu de bagage supplémentaire sur l'événement, voir :

Pour les journaux de « voyage » d'autres participants, voir :

Début du contenu technique

Je vais mettre le contenu technique dans des blocs les mettant comme celui-ci. Si vous ça ne tombe pas dans vos cordes, passez par-dessus.

Fin du contenu technique

La semaine précédant l'événement

CppCon est un très gros événement, qui se tient chaque année depuis 2014 (vous trouverez mes journaux des années précédentes sur index.html avec des noms évocateurs tels que cppcon2014.html par exemple). Je participe à l'organisation de l'événement depuis le début, mais le maître d'oeuvre est Jon Kalb, et l'autre pesque maître d'oeuvre est Bryce Adlestein-Lelbach. Nous avons tenu l'événement à Bellevue, en banlieue de Seattle, pendant plusieurs années, avant de le déplacer à Denver en 2019 par besoin d'espace (l'hôtel où nous sommes maintenant est gigantesque). En 2019, nous avions plus de 1200 participantes et participants sur place; pour un colloque aussi spécialisé, c'est impressionnant.

Depuis le début, CppCon offre non-seulement des conférences (et beaucoup! Environ six ou sept en même temps de tôt le matin à tard le soir pendant cinq jours consécutifs, hormis les Keynotes où tout le monde assiste) mais aussi des classes de maître, pré-conférence et post-conférence. J'en donne d'ailleurs moi-même depuis 2016. Ces classes se donnent habituellement la fin de semaine qui précède l'événement et celle qui le suit, ce qui fait de l'événement entier (classes incluses) quelque chose qui se tient sur neuf jours consécutifs.

Cette année, dû au format virtuel de l'événement, les classes de maître se donnent la semaine avant et la semaine après. La mienne, intitulée Managing Memory (https://cppcon.org/class-2020-managing-memory/), eut lieu la semaine précédant la conférence, et j'ai réussi à organiser l'horaire pour être en mesure d'offrir aussi mes cours de jour et mes cours de soir (ouf!). Ce fut costaud sur la voix! Mais je me suis bien amusé. La classe était en partie faite de participants européens et de participants américains, alors on jonglait entre le cours du soir (Europe) et le cours de jour (États-Unis). C'était costaud, mais je pense que les gens ont apprécié.

Un gros merci au passage à mes étudiantes et à mes étudiants, qui collaborent avec moi quand je dois m'absenter comme ça, et qui s'adaptent aux petites acrobaties d'horaires et de format des cours qui viennent avec le fait de m'avoir comme enseignant. J'apprécie votre ouverture.

J'ai appris au passage que malgré le format et les circonstances complètement atypiques de 2020, nous serons plus de 920 participantes et participants cette année. Tout de même!

Jour 0 13 septembre

Il y a toujours une réception au début d'un événement comme CppCon. Le but visé est de briser la glace, faire en sorte que les gens se rencontrent et socialisent un peu, surtout celles et ceux pour qui c'est une première fois. Habituellement, un accueil se fait en après-midi, alors que les gens arrivent de leur avion, viennent prendre possession de certains objets offerts par les commanditaires de l'événement (un sac, du Swag, parfois des livres, des vêtemements, etc.) et saluer des gens rencontrés par le passé puis aller manger une bouchée. Le soir, un événement plus social se tient (avec alcool, mais en quantités limitées – le reste est aux frais des gens), des bouchées, une exposition d'affiches de gens ayant soumis une proposition digne d'intérêt (projets étudiants de qualité, produits qui souhaitent se faire connaître). On casse la glace, on bavarde, on s'amuse un peu avant la semaine très intense qui nous attend.

Cette année, l'événement se tient à travers Remo (https://remo.co/), un outil imparfait mais tout de même intéressant qui permet de créer des salles de rencontres virtuelles, de s'assembler par table et par étage (il y a plusieurs étages par salle), et d'entretenir des conversations audio et vidéo avec les gens assis avec nous. Pour familiariser les gens avec l'outil, nous avons tenu un accueil le dimanche après-midi (à mon heure) dans la salle commune, avec des présentations de certains Lightning Talks du passé dans diverses salles – un Lightning Talk est une présentation de courte durée; les participants à la conférence peuvent en proposer, et on tient des séances où plusieurs s'enchaînent à deux ou trois reprises chaque jour. C'est très dynamique et souvent très amusant.

J'ai pu bavarder avec quelques personnes, dont mon ami Billy Baker (maintenant Co-Chair de LEWG), Inbal Levi (qui siège sur WG21 pour Israel et est aussi Co-Chair de LEWG), Vishal Oza, Guillaume Matte (à qui j'ai eu le plaisir d'enseigner il y a bien longtemps; il est chez UbiSoft Montréal maintenant mais demeure toujours aussi sympathique) et Paul Licameli d'Audacity, très sympathique même si je n'ai pas pu lui parler longtemps (je devais aller chercher mon garçon Ludo chez un ami). Particulièrement content de parler avec la sympathique Inbal Levi, que j'ai croisé à quelques reprises mais avec qui je n'avais pas eu l'occasion de converser encore.

Ce fut humble mais sympathique, et nous avons pu constater que la mécanique de l'événement semblait pouvoir tenir la route.

Jour 1 14 septembre

Journée un peu plus courte qu'à l'habitude aujourd'hui. De un, nous avons moins de séances de soirée cette semaine (le format à distance se prête moins à ces excès), et de deux, exceptionnellement, la première présentation de la journée est en milieu d'avant-midi.

Je prends place à une table où se trouve Tony Van Eerd (je lui demande, à la blague, si on voit bien de cet endroit, mais ma blague tombe à plat car il n'est pas là; seul son avatar occupe un siège). Je suis rejoint par Hana Dusíková, qui m'avoue avoir décidé de venir au colloque à la dernière minute (elle sera d'un panel demain matin), Inbal Levi et Guillaume Matte. Nous bavardons un peu jusqu'à ce que la musique débute.

Il faut savoir que CppCon a un House Band qui joue des pièces du répertoire classique dans le genre dans la salle de plénière depuis la toute première année de l'événement. Normalement, avant et après un Keynote, le groupe joue alors que nous nous installons avec un fruit, un yogourt et un café (parfois des bagels) le temps que tout soit en place. Ce même groupe a donc joué pendant une trentaine de minutes ce matin, mais a malheureusement coupé court à notre conversation (une musique de fond aurait peut-être été plus approprié, mais je comprends que l'on ait souhaité maintenir cet aspect l'expérience habituelle).

Vient un moment où quelqu'un (Marco Arena? Je ne suis pas sûr) écrit, sur le clavardage général, un petit Hello from Italy... et ça explose! Charmant passage d'une dizaine de minutes où les "hello", les "hi", les "bonjour" et autres de divers endroits dans le monde pleuvent. J'ai fait un grand sourire. Il y a quelque chose de beau dans ce soutien au colloque.

Jon Kalb prend la parole vers 10 h 45 EST. Ça coupe la musique un peu brusquement. On est presque 1000 personnes à participer, apparemment. Le code de conduite (Code of Conduct, CoC) est  présenté par Céline Dedaj, avec soutien par Sy Brand et Guy Davidson. C'est clair, sympathique et bien présenté. Un courriel spécifique a été mis en place pour les gens qui vivent un événement déplaisant, et il est possible de les rejoindre (eux ou les bénévoles de l'événement) à travers des messages privés. Une discussion / présentation suit, avec une brève discussion des chocolats préférés de chacun.

Jon Kalb revient sur les raisons d'être présente ou présent à un événement comme CppCon. Ce n'est pas seulement pour les présentations (elles seront toutes publiées sur YouTube éventuellement), c'est surtout pour les gens.

Bjarne Stroustrup prend ensuite le plancher...

Vidéo : https://www.youtube.com/watch?v=ERzENfQ51Ck&feature=youtu.be

Bjarne Stroustrup – The Beauty and Power of "Primitive" C++

Bjarne Stroustrup explique qu'avec un événement différent de l'habitude, il comptait faire une présentation différente de ses habitudes aussi. Moins de philosophie et de principes, plus de plaisir avec le code. Il compte parler de mapping de bytes sur des messages. Le plaisir et les frustrations du code de bas niveau, en quelque sorte.

Bjarne Stroustrup présente les contraintes auxquelles nous serons soumis. De manière générale, il y a toujours des contraintes (basse latence, pouvoir consommer le message avec d'autres langages, réduire la consommation d'espace mémoire, etc.). Il compte mettre l'accent sur la séparation de la consommation et de la production d'un message du problème du transport de ce message. Le point focal est l'interface de messagerie simple qui réalise le marshalling, que ce dernier passe par un canal, de la mémoire partagée ou autre chose.

Le modèle de communication de Bjarne Stroustrup fonctionne par session. Chaque message n'a pas à être autodescriptif (les informations de version et autres sont échangées une fois par session seulement). Les messages ne contiennent que des primitifs, mais pas de pointeurs et aucune paire de références mutuelles. Il nomme ces structures des Flats. Un Flat a une en-tête descriptif bref, un corps et, de manière optionnelle, une queue (utile pour les messages de longueur variable). Il fait circuler des primitifs, des variants, des optionnels, des vecteurs, des tableaux de taille fixe, etc.

Bjarne Stroustrup explique que le type-mapping en soi est mieux produit par des spécialistes ou des programmes; c'est pas un boulot pour des humaines ou des humains. Il a des types pour Flat qui correspondent à ses cas d'utilisation.

Bjarne Stroustrup nous dit au passage qu'il s'ennuie de discuter avec des gens autour d'une ardoise.

Bjarne Stroustrup poursuit en expliquant le besoin d'un IDL pour abstraire les types impliqués et faciliter le travail multi-langages, et d'une processeur de langage générant du code culturellement approprié aux langages de destination à partir de cet IDL.

Bjarne Stroustrup : « To be fast and correct, code has to be small and simple ». Il pique les Frameworks immenses au passage (son projet entier tient sur 2000 lignes de C++ environ), mais a l'honnêteté de présenter les avantages et les inconvénients.

Il présente ensuite les aspects de Flats dont il souhaite nous parler, en particulier le traitement des erreurs. Le premier thème dont il parle est les interfaces, au sens du code qu'on écrit (naturellement) pour utiliser Flats. Il vise une seule interface pour plusieurs implémentations (!). Les enjeux du design sont expliqués (dans le clavardage, des gens pensent qu'il réinvente la roue; je pense qu'ils en comprennent pas l'intention de la démarche, en particulier le souhait de ne pas se commettre à un seul vendeur, quel qu'il soit, et l'expérimentation pédagogique derrière la démarche).

Bjarne Stroustrup présente ses Views, pour ne voir que les parties d'un Flat qui l'intéressent. C'est intéressant.

Bjarne Stroustrup présente la stratégie de tests qu'il a appliquée pour choisir des modalités pertinentes de lecture et d'écriture. C'est très instructif. Entre autres, certains trucs simples comme des accesseurs doublent le temps d'accès dans certains cas (les optimiseurs ne parviennent pas à tout enlever ce qui est redondant).

Son processeur de langage génère à la fois un message et un descripteur de message, qui connaît la structure du message. Placement new sert beaucoup dans son code. Ses messages peuvent avoir une taille inconnue a priori, mais cette taille est immuable post-construction. L'allocation de la mémoire pour tenir compte de cette queue de taille variable repose sur un allocateur.

Bjarne Stroustrup mentionne l'omniprésence de () dans le code. Il dit vraiment vouloir operator.(), qui aurait grandement facilité son travail.

Bjarne Stroustrup a choisi des chaînes de caractères de taille fixe (20 caractères), limitées à un byte par caractère, et utilise des vecteurs de char pour les chaînes plus longues. C'est un enjeu économique, vraiment.

(je vois un gestionnaire d'erreurs constexpr dans le code... Tiens tiens). C'est expect(C,error_code) qui couvre trois cas (logging, throwing et terminating, choisi en tant que premier paramètre du template).

Bjarne Stroustrup montre comment il a testé la vitesse d'exécution de son choix de chaînes de caractères. Bravo pour intégrer ceci dans sa démarche, et pour le montrer.

Bjarne Stroustrup utilise des Spans pour exposer les chaînes de caractères et les vecteurs, dans le but d'offrir une interface homogène. Il a à la fois Span et Span_ref pour des cas où une indirection tenant compte du descripteur de message est utile.

Bjarne Stroustrup suit avec une discussion des enjeux ayant trait à l'initialisation : équilibre entre le temps, l'espace et la sécurité. Entre autres, tout initialiser par défaut est une mauvaise idée (ce dont je parlerai plus tard cette semaine); ça coûte trop cher, et il n'est pas clair que zéro soit toujours sage.

C'est une présentation intéressante de la pensée d'un expert, et d'un individu expérimenté, portée sur des enjeux de conception et d'architecture. Il y aura des critiques (plusieurs n'écoutent pas avec l'angle proposé, préférant un angle personnel mais disjoint de l'intention derrière le propos), mais j'ai beaucoup aimé.

Bjarne Stroustrup fait aussi une autocritique : mêler arithmétique signée et non-signée est douloureux. Il aurait dû utiliser plus de concepts (les erreurs dans le code générique sans concepts sont difficiles à pister). Faire des bêtises en écrivant du code dépendant de l'ordre d'évaluation des paramètres peut faire mal. Jolie phrase : « The bug is always where you are not looking ». Les transtypages sont nécessaires, mais mieux vaut s'en tenir au minimum. Le bit-fiddling est nécessaire, mais difficile à faire sans se tromper.

Bjarne Stroustrup complète en expliquant pourquoi Flats n'est pas proposé pour standardisation : ce ne sont pas toutes les bibliothèques qui sont pertinentes pour standardisation! Cela dit, il estime (avec raison) que son expérimentation démontre que C++ est tout à fait approprié pour faire correspondre les abstractions à la réalité du matériel.

Bjarne Stroustrup tiendra un AMA mercredi; il recevra les questions à ce moment.

Bjarne Stroustrup termine vers midi EST. La musique reprend, et je me dirige vers la salle Embedded pour une présentation de Dan Saks. Au passage, je me fais chauffer des rests (poivrons farcis, mioum!) et j'aide mon amoureuse Za avec quelques tâches ménagères... et la mise à mort d'une araignée.

Les gens à ma table bavardent et sont sympathiques, mais je mange mon dîner alors je leur épargne ma caméra.

Vidéo : https://www.youtube.com/watch?v=uwzuAGtAEFk&feature=youtu.be

Dan Saks – Memory-Mapped Devices as Objects

Dan Saks nous informe qu'on parlera concrètement de la rédaction de pilotes, car les appareils dont nous parlerons apparaissent comme des appareils externes aux yeux des programmeuses et des programmeurs.

Dan Saks distingue control registers, status registers, transmit registers et receive registers, et dit qu'il utilisera un appareil à six registres pour son exposé (il décrit cet appareil). Il mentionne l'évolution du vocabulaire (port addressing, memory mapped registers) et explique comment ces registres fonctionnent. Une illustration de l'espace adressable suit (bien). Entre autres, les memory mapped registers sont typiquement dans une adresse haute, loins du vecteur d'interruptions.

Dan Saks explique qu'il est facile de mal utiliser ces registres (mal les lire; mettre l'appareil dans un état incorrect; provoquer une opération inadéquate) en manipulant mal les bits. Ça explique l'intérêt d'utiliser des abstractions à coût nul comme celles que propose C++.

Dan Saks propose de payer maintenant (en définissant des types pertinents) plutôt que plus tard (bris, bogues suspects). On risque d'utiliser l'appareil plus souvent qu'on ne conçoit le logiciel, alors c'est économiquement sain.

Dan Saks dit suivre quelques principes de design : « Make interfaces easy to use correctly and hard to use incorrectly » (Scott Meyers), « Program in a style that turns run-time errors into compile-time errors » (Dan Saks)

Dan Saks suggère <cstdint> et les types de taille fixe pour l'exercice (un homme sage!), et recommande des alias (using) pour clarifier le propos et élever le niveau du discours.

Dan Saks entre ensuite dans le coeur du propos, ce que j'ai touché dans mes cours : comment placer un objet à l'endroit approprié en C++. Il mentionne ce qu'il nomme at-placement, un mécanisme compile-time offert par certains compilateurs à titre d'extension, mais penche plus pour des solutions portables. Il mentionne aussi une technique reposant sur des variables extern, prise en charge par l'éditeur de liens (on est donc hors de la machine abstraite); selon lui, côté vitesse, c'est souvent un pire cas. Une autre approche est de placer un pointeur manuellement à l'adresse souhaitée (pointer placement), ce qu'il fait avec un pointeur constexpr mais sa manoeuvre est illégale en C++ (ça exige un reinterpret_cast, qui nous donne du implementation-defined behavior et n'est donc pas acceptable). Dan Saks propose aussi une approche qui placerait une référence à une zone mémoire, reference-placement, qui fonctionne mais pas constexpr.

Dan Saks passe ensuite à une approche où les registres ont des types distincts, pour réduire les risques d'accidents, par exemple lors d'appels de fonctions prenant des registres en paramètre : faire des classes, et encapsuler les registres.

Dan Saks rappelle que les opérations sur des registres peuvent entraîner des effets de bord, donc qu'il faut prévenir certaines optimisations qui pourraient supprimer du code important. Utiliser volatile est sage ici. Il montre comment appliquer volatile au bon endroit pour un pointeur ou une référence : mieux vaut s'assurer qu'il s'applique au type, pour éviter d'oublier la qualification sur une opération importante par inadvertance. Un truc est de définir la classe non-volatile, puis de faire un alias pour un équivalent volatile du même type. Faut envisager des méthodes volatile, évidemment. Mieux encore : faire des alias pour les registres eux-mêmes (des UART) des entités qualifiées volatile.

Dan Saks recommande de valider que la disposition du type représentant l'appareil soit conforme au matériel, et dit que s'assurer d'un Standard Layout Type est important pour y arriver. Entre autres, faut s'assurer que tous les états soient groupés dans une même région de qualifications d'accès. Il montre un truc intéressant avec attributs protégés et héritage privé (bravo!), dans la mesure où les classes dérivées n'ont pas d'attributs d'instance. Dan Saks recommande static_assert(is_standard_layout_v<T>) pour garantir que notre code respecte le contrat.

Dan Saks aborde ensuite la délication question du Padding, qui peut briser la disposition choisie. Il n'existe pas de manière portable d'empêcher ce comportement. Il est par contre possible d'utiliser des mécanismes non-portables pour y arriver, et il est possible de valider la disposition attribut-par-attribut avec static_assert et offsetof. Il est même parfois possible de simplement vérifier que la taille totale du type correspond à la somme des tailles des attributs, tout simplement.

Dan Saks : les constructeurs sont idéaux pour initialiser les registres modélisés par un type donné. Il en profite pour introduire Placement new. Il l'applique suivant un pointer-placement ou un reference-placement. Ensuite, il montre comment utiliser un new sous forme de méthode pour alléger l'écriture pour le code client (charmant : il fait simplement return reinterpret_cast<type_de_registre>(adresse)! Beaucoup de réactions positives dans le clavardage). Il s'amuse même avec un opérateur new sous forme de méthode prenant un déplacement (offset) en paramètre additionnel pour réduire la redondance, et montre qu'avec une énumération on peut faire quelque chose de franchement bien.

Du beau travail; en plus, ça renforce le message de mon cours la semaine dernière! Emmanuel Thivierge (un sympathique ancien du DDJV) est présent. On échange par clavardage pendant les présentations.

Discussions animées à ma table par la suite. Dan Saks a vraiment stimulé les esprits.

Vidéo : https://www.youtube.com/watch?v=SbQVY-JOrgg&feature=youtu.be

Ilya Burylov et Michael Wong – The future of C++ Parallel and Concurrency Safety Guidelines

Michael Wong présente Ilya Burylov, puis se présente lui-même. Comme toujours, il remercie un tas de contributeurs et explique la présence de logos de compagnies dans sa présentation.

Michael Wong : on aura trois grands thèmes, soit Que faire quand on ne peut pas tout tester? Est-ce que la GSL et MISRA C++ suffisent pour couvrir les bogues de concurrence? et (j'ai manqué le dernier)

Michael Wong : on teste et on teste et on teste... mais il existe plusieurs domaines concrets et importants pour lesquels réaliser des tests exhaustifs est impossible. Pour ces cas, on applique une approche SIL, qui fait correspondre des actions en réaction à la gravité des situations. SIL niveau 0 correspond à ISO 9001. MISRA suit la nomenclature SIL.

Michael Wong aborde la question de la gestion de la mémoire allouée dynamiquement, de même que celle de la gestion des exceptions. En particulier, MISRA C++ 14-8-1 proscrit l'allocation dynamique de mémoire, du moins à partir d'un tas général. Des implémentations déterministes et non-sujettes à fragmentation sont permises.

Michael Wong poursuit avec l'enjeu des bogues de concurrence et des conditions de course. On peut les éviter en désactivant les interruptions autour de certaines opérations... Un cas répertorié d'accélération non-désirée d'un véhicule à la NASA est rapporté et décrit, découlant d'un bogue de concurrence (il y a eu du code spaghetti et des accès non-volatiles à des états globaux partagés).

Michael Wong aborde ISO 26262 sur la sécurité automotive.

Pour ce qui a trait à la GSL, elle vise la transition de code C++ vieillissant vers du code C++ moderne. Michael Wong présente certains des grands principes de la GSL (plusieurs rejoignent la présentation de Dan Saks). En particulier, la section sur la concurrence et le parallélisme de la GSL est l'une des moins complètes. Michael Wong en profite pour faire un appel à l'aide!

Michael Wong liste une quinzaine de guides de programmation sécuritaire en C++, et examine les forces et les faiblesses de certaines d'entre elles. Gentille mention des travaux de WG23 au passage. La plupart sont datées...

Michael Wong fait un bref historique de MISRA C++, insistant sur le fait que les règles de MISRA doivent être vérifiables statiquement. Il parle de l'implication de gens de WG21 et d'experts de C++ dans ce processus d'actualisation.

Ilya Burylov explique pourquoi des règles de sécurité sont requises, et dans quels domaines ce besoin est le plus criant.

Ilya Burylov montre les grandes catégories de règles en cours de discussion. Les règles décidables iront à WG23 directement; certaines défectuosités sont signalées à WG21.

Ilya Burylov présente ensuite la structure des règles. Un exemple concret de règle (Do not call std::thread::detach() function) est donné, puis expliqué. Un autre exemple de plus haut niveau (Do not use std::thread) suit. Selon la gravité du problème signalé, les efforts de documentation requis pour contourner une règle seront plus ou moins grands. Une autre règle recommandant de n'utiliser que des atomiques séquentiellement cohérentes suit.

Michael Wong reprend le plancher et apporte un correctif : le problème n'est pas dans les mécanismes mais dans les gens qui les utilisent. La réaction est positive dans le clavardage. Michael Wong rapporte des bogues dans la spécification du standard qui ont été détectés par une relecture attentive.

Michael Wong poursuit avec une discussion de la sécurité dans les API pour accéder aux GPU. S'ensuit un coup d'oeil sur la situation actuelle : nous avons beaucoup de règles et de recommandations, mais très peu pour les enjeux de parallélisme et de concurrence. Il termine par un appel à l'aide.

: Is a complete ban on dynamic allocation too limiting for modern software systems then? How can someone prove that custom allocators meet the Autosar guidelines?

Michael Wong : je m'attends à une modernisation des règles de MISRA sur la base des travaux d'Autosar, p. ex. : garantir un WCET ou garantir l'absence de fragmentation. Ilya Burylov : la clé est de documenter comment le code réagira à un échec d'allocation. Pour ce qui est des allocateurs, certains cas spécialisés, p. ex. : monotonic peuvent être démontrables.

Q : How can we take advantage of those safety guidelines in user applications?

Michael Wong : si on parle des règles existantes, plusieurs outils les vérifient et génèrent des diagnostics lors de contraventions. Pour les nouvelles règles, les outils sont encore à développer dans certains cas. Notez que certaines techniques comme le Double-Checked Locking, bannie par les règles de MISRA, sont très difficiles à détecter statiquement

Q : What efforts exist to shape the design of the C++ language based on these safety considerations to take a more proactive approach to ensuring safety?

Michael Wong : nous avons plusieurs groupes qui planchent sur ces questions (il en nomme quelques-uns). Michael Wong distingue le standard, qui dessert une vaste communauté, et les enjeux de sécurité qui sont parfois plus intéressants pour des sous-groupes de cette communauté, et peuvent être hostiles aux besoins de la majorité

Q : How do we get involved?

Michael Wong : contactez-moi par courriel! 

Michael Wong¸ a fait de l'excellent travail, comme toujours. Je change de pièce, allant vers count_if, et je bavarde sur deux canaux différents avec Billy Baker et Emmanuel Thivierge.

Vidéo : https://www.youtube.com/watch?v=tWvaSkgVPpA

JF Bastien – Just-in-Time Compilation

JF Bastien est très élégant. Il a soigné son environnement aussi. Il dit souhaiter couvrir une vingtaine de papers sur le sujet. Un lien github est offert.

JF Bastien commence par une présentation ce que qu'est un JIT, en comparaison avec un AOT. La plupart des gens voient C++ comme un modèle AOT. Il positionne un interpréteur vis à vis un JIT ou un AOT, et place un CPU comme un interpréteur de code machine; un compilateur fait aussi des évaluations partielles de code, et est en quelque sorte lui-même un interpréteur.

JF Bastien dit avoir trois buts aujourd'hui : placer JIT et AOT dans un continuum; voir ce que nous ont apporté les JIT; que pourraient nous apporter les JIT. Il ne souhaite pas offrir une critique des JIT aujourd'hui (c'est un autre sujet). Il fait plusieurs clins d'oeil à Alice au pays des merveilles (merci JF!)

A brief history of Just-in-time (2003), qu'il dit excellent. Il parle du temps perçu : un JIT qui prendrait une seconde à évaluer une expression serait insupportable; un compilateur traitant un programme en une seconde est merveilleux. Les JIT amènent des enjeux d'équilibre entre l'espace et le temps

JF Bastien parle de quatre enjeux :

JF Bastien présente les premiers JIT selon lui, dans une perspective historique. Recursive Functions of Symbolic Expressions and their Computation Machine (1960). Regular Expression Search Algorithm (1968, Ken Thompson). Efficient Implementation of the Smalltalk 80 System (1984), qui apporte l'idée d'un IR. Optimizing Dynamically-Typed Object-Oriented Languages with Polymorphic Inline Caches (1991), que JF Bastien présente comme un précurseur de JavaScript. DPF (1994), qui génère dynamiquement du code de traitement de paquets. Exokernel (1995), qui remet en question une vision traditionnelle de l'exposition des services d'accès au matériel (DPF fait partie de ce système)

JF Bastien fait un aparté à propos de ATOM (1994), qui discute de l'instrumentation des programmes. Il poursuit avec EMBRA (1996), un simulateur de processeur et de cache, plus lent qu'un véritable processeur, mais par un facteur décent (approximativement 20) et permet de réfléchir un nouveau processeur avant de le mettre en production. Dynamic Optimization (1999) avec Oberon 3, qui réorganise dynamiquement l'ordre des champs dans un objet (un thème récurrent est qu'il est souvent préférable de déterminer quoi optimiser plutôt que quand optimiser; JF Bastien mentionne AoS vs SoA mais dit que ce n'est que la pointe de l'iceberg). DYNAMO (2000), qui fait des optimisations dynamiques aussi; JF Bastien indique que DYNAMO peut faire un JIT d'un JIT et est théoriquement appliquable à lui-même.

JF Bastien passe ensuite à Java et de Compiling Java Just in Time (1997). C'est une discussion intéressante, qui parle de l'importance d'un bon IR pour avoir un bon JIT. Design of the Hotspot Client Compiler for Java 6 (2006). Une discussion fort intéressante.

JF Bastien passe à FX!32 A Profile-Directed Binary Translator (1999), qui permettait d'exécuter des applications x86 sur un DEC Alpha (ça semble être une première apparition d'optimisation guidée par profil). TRANSMETA (2000), qui faisait du logiciel de CodeMorphing; JF Bastien fait remarquer que ce modèle supportait une forme de mémoire transactionnelle. QEMU (2005), qui traduit de processeur à processeur. VALGRIND (2007), qui porte une attention particulière aux Shadow Values. Trace-Based Just-in-Time Specialization for Dynamic Languages (2009), qui discute de JavaScript.

JF Bastien approche de la fin, et ouvre la boîte de Pandore de la sécurité. Il passe rapidement sur Native Client (2009), qui a donné naissance à NACL. Attacking Client Side JIT Compilers (2011), dont le titre dit bien l'intention. EMSCRIPTEN (2011), pour compiler de LLVM à JavaScript. Enfin (et bien sûr), WebAssembly (2017)

Ouf, beaucoup de contenu, fort intéressant (j'ai le goût de lire ou de relire tout ça). Je dois arrêter pour aujourd'hui et m'occuper un peu des enfants et du souper...

Jour 2 15 septembre

Pour diverses raisons, je suis arrivé un peu à la dernière minute ce matin alors j'ai tout juste eu le temps de préparer mon plan de match avant que ne débute le premier événement de la journée...

Committee Fireside Chat

Les participants sont Herb Sutter, Bryce Adelstein Lelbach, Michael Wong, Bjarne Stroustrup, Inbal Levi, JF Bastien, Hana Dusíková, JC Van Winkel et Tony Van Eerd et c'est Herb Sutter qui démarre le « tour de table » par lequel le groupe se présente. Je n'ai pas tout noté de ce tour de table, j'espère que vous ne m'en voudrez pas trop.

Q : pourquoi C++ n'est-il pas mort?

Bjarne Stroustrup : j'en ai parlé dans mon texte de HOPL. J'ai eu des craintes vers 2005, je dois l'avouer. Il y a toujours eu de la compétition pour C++. La raison de la survie de C++ est que tout le monde voulait s'éloigner du matériel; il y avait des créneaux pour certains langages, mais C++ est ce qu'il faut pour fonctionner partout

Q : quel est le plus grand défi pour l'éducation avec C++?

JC Van Winkel : C++ peut faire peur au début. Il y a une forme de Choice Stress, avec plusieurs options pour résoudre un problème. SG20 essaie d'aider les formatrices et les formateurs à préparer un curriculum pertinent et cohérent, et à définir des profils de sortie pertinents. Nous cherchons aussi à influencer le comité dans ses démarches, moussant les Audience Tables de Gor Nishanov et les Tony Tables de Tony Van Eerd

Bjarne Stroustrup : trop de gens essaient de montrer des techniques avancées trop rapidement. J'aimerais voir plus d'articles destinés à des débutant(e)s. Le livre classique de C, K&R, est un bon exemple

JC Van Winkel : plusieurs apprennent Python parce que c'est facile à apprendre. Je pense toutefois que le C++ moderne, particulièrement C++ 20, permet d'exprimer clairement et simplement des idées non-triviales.

Q : quelle est la partie la moins bien comprise de C++?

Hana Dusíková : (je n'ai pas compris, zut)

Michael Wong : il y a trop d'exemple compliqués. Par exemple, nous avons proposé les Ranges aux gens de l'industrie du jeu, et la réaction fut négative, mais je pense que le choix d'exemple a beaucoup joué dans cette réaction. Pour la concurrence et le parallélisme, nous sommes encore en exploration.

Bjarne Stroustrup : plusieurs pensent qu'il faut une hiérarchie de classes pour faire du C++. C'est un erreur; cela mène à de la complexité inutile.

Inbal Levi : je pense que la force de C++ est qu'il s'agit d'un langage de programmation système, et qu'il permet de penser efficacement au matériel. Comprendre la différence entre Compile-Time et Run-Time est important en C++

Michael Wong : le développement de systèmes embarqués est crucial pour C++

Q : C++ n'offre pas de standard de facto de logging...

Bryce Adelstein Lelbach : plusieurs choses pourraient être ajoutées à la bibliothèque standard, mais en C++, ce qui doit y aller est : les outils « à très haute valeur » comme les types vocabulaires (types communs sur lesquels tout le monde s'entend, p. ex. : string_view ou optional); les facilités qui interfacent avec la plateforme et permettent d'élever la pensée (p. ex. : les facilités de concurrence); les entités qui requièrent un support langagier (p. ex. : type_traits). Ce sont les priorités pour nous, car seule la bilbiothèque standard peut vraiment les couvrir. Pour du logging, il se peut que des bibliothèques tierces soient plus appropriées. Je pense toutefois que rendre plus simple l'intégration d'outils tiers partis est essentiel.

Q : quelles sont les bibliothèques qui manquent vraiment au standard?

Tony Van Eerd : à propos du logging, j'ai rarement vu un excellent logger. Si on devait un choisir un pour standardisation, ce serait embêtant. Par contre, un bon logger pourrait bénéficier du support du compilateur... Pour un logger, on pourrait aussi bénéficier des contrats (callbacks en cas d'échecs). Je peux voir la valeur d'un logger standard, personnellement. Ce qui est certain, c'est qu'un Package Manager serait diablement utile.

Q : que doit-on attendre de C++ 23 avec la pandémie?

JF Bastien : nous avons un Bold Plan de priorités, prévu avant la pandémie, qui est utile pour nous guider. Nous avons des rencontres hebdomadaires dans lesquelles nous cherchons à corriger des bogues; les Big Features sont plus difficiles à réfléchir à distance. Les priorités en termes de Big Features sont la réflexivité et le Pattern Matching. Nous visons 2023, mais nous ne savons pas si nous aurons l'expérience terrain pour y arriver.

Bjarne Stroustrup : j'aimerais que nous ayons un logger standard, personnellement. D'autres langages ont de bons mécanismes de distribution et n'ont pas le processus ISO à respecter. Je ne suis pas certain que le support d'un compilateur soit requis pour du logging; je pense que si nous avions un bon mécanisme de distribution, le logging suivrait

Q : comment pourrions-nous aider avec la GSL?

Bjarne Stroustrup : c'est une bonne question. Nos emplois respectifs nous ralentissent. Les Core Guidelines sont très haut dans mon échelle de priorités, mais ma liste d'urgences est très longue et ça nous ralentit. Utilisez les Core Guidelines et donnez-nous une rétroaction détaillée

Q : est-ce utile pour aider les Core Guidelines de pousser notre entreprise à les adopter?

Bjarne Stroustrup : oui. Intégrez-les par étapes. Les analyseurs statiques vous aideront. Microsoft a fait du progrès de ce côté.

Michael Wong : si vous avez de l'expertise dans un domaine, par exemple la programmation concurrente, contactez-nous. Aussi, plus les règles sont spécifiques et vérifiables statiquement et plus elles sont utiles.

Bryce Adelstein Lelbach : la plus importante innovation dans notre processus est que nous avons un ensemble plus clair de priorités, un plan. Notre comité est grand, et ce focus accru est essentiel pour la progression de C++. En tant que Chair de LEWG, j'apprécie cette direction

Q : le Core Language est plus gros et plus compliqué à chaque version du langage. Souhaitez-vous simplifier le langage?

Bjarne Stroustrup : nous ne pouvons pas. Il y a des millions de gens qui dépendent du langage. Ces gens veulent plus d'outils, mais je veulent pas que l'on brise leur code. Nous pouvons améliorer l'éducation, surtout pour les débutant(e)s, et offrir de meilleurs outils, particulièrement pour l'analyse statique

Michael Wong : on n'a pas à comprendre tout C++ pour réaliser des tâches. Sur le plan éducatif, on peut tracer des chemins qui rendent C++ plus accessible

Inbal Levi : la simplicité est moins importante pour moi que la capacité d'expliquer clairement nos idées et nos intentions. Cela bénéficie aussi au monde de l'éducation

Q : à quoi s'attendre de C++ 23?

Bryce Adelstein Lelbach : nous livrons à date fixe. C++ 23 contiendra ce qui est prêt à ce moment

Tony Van Eerd : C++ 20 est gigantesque. Il peut être sage de prendre le temps de nettoyer les détails obscurs et raffiner ce que nous venons de livrer. Il est difficile de participer à toutes ces rencontres en ligne

Bryce Adelstein Lelbach : notre plan demeure le plan

Michael Wong : les informaticien(ne)s fonctionnent bien à distance 🙂

Bjarne Stroustrup : j'ai besoin de voir des gens pour progresser et rester connecté. C++ 14 a poli les contours de C++ 11; il se peut que C++ 23 fasse de même pour C++ 20

Herb Sutter : C++ 20 est la première fois que C++ a tous les éléments clés décrits dans D&E en 1994 (sauf peut-être UFC). C'est quand même un exploit

Bjarne Stroustrup : le texte de HOPL est en quelque sorte la suite de D&E

Q : est-on au point où briser la rétrocompatibilité serait le seul moyen de simplifier le langage?

Tony Van Eerd : plusieurs pensent que nous ne pouvons pas changer des éléments clés (initialiser les variables par défaut, être const par défaut, avoir des constructeurs explicites par défaut)... Il est possible de changer ces choses, mais c'est un chemin qui se fait sur une vingtaine d'années. Par exemple, on introduit un mot clé (implicit, disons). Plus tard, les compilateurs commencent à rapporter l'absence de soit explicit, soit implicit... Éventuellement, explicit devient le défaut... mais on parle d'une vingtaine d'années, vraiment

Bjarne Stroustrup : il a fallu une vingtaine d'années pour introduire certaines idées. Faire un changement local à une compagnie est simple en comparaison avec faire une changement dans un standard qui impacte des millions de programmeuses et de programmeurs. C'est le prix du succès

JF Bastien : les petits changements sont plus simples à apporter. Les outils peuvent nous aider. Par exemple, raffiner les diagnostics et l'analyse statique permet de faire évoluer le code par des suggestions.

Inbal Levi : un langage permet à une programmeuse et à un programmeur d'exprimer ses idées. Nous devons choisir la liberté que nous voulons leur donner

Hana Dusíková : parfois, le design est solide mais l'implémentation est fragile.

Q : deux questions se ressemblent : comment puis-je contribuer aux travaux du comité?

Bryce Adelstein Lelbach : normalement, nous recommandons aux gens de venir aux rencontres in vivo, mais en période de pandémie... Vous pouvez prendre une proposition qui vous intéresse et pour laquelle vous avez des idées, contacter l'auteur, et faire votre chemin en travaillant sur une proposition

Michael Wong : SG14 et SG19 sont des groupes « ouverts » dans lesquels il est possible de contribuer sans devenir membre officiel du comité

JC Van Winkel : c'est pas mal la même situation avec SG20. Participez, joignez-vous à notre liste de diffusion

Q : existe-t-il un site montrant des exemples de C++ 20?

JF Bastien : cppreference fait un excellent travail.

Tony Van Eerd : j'ai des Tony Tables sur mon site, mais C++ 20 est énorme alors je n'ai pas tout; cppreference est le meilleur endroit pour ça

Bjarne Stroustrup : les exemples sont importants, mais les concepts et les idées sont plus important(e)s qu'une liste de petits outils. J'utilise cppreference tout le temps pour les détails, moi aussi

Inbal Levi : une compréhension plus large des idées et plus importante qu'une connaissance des détails, je suis d'accord

Herb Sutter : qu'est-ce qui vous semble le plus excitant dans C++ maintenant?

Hana Dusíková : les conteneurs constexpr

Michael Wong : accroître la place de C++ dans les systèmes embarqués

Bjarne Stroustrup : les coroutines

JC Van Winkel : profiter des abstractions de haut niveau sans perdre le contact avec le matériel. Le quoi plus que le comment

Bryce Adelstein Lelbach : les exécuteurs, les outils et les modules

Inbal Levi : C++ 20 change la manière de programmer. Les concepts à eux seuls sont majeurs

JF Bastien : accroître la sécurité et rendre le langage plus facile à utiliser, sans que cela ne réduise la « performance »

Tony Van Eerd : ajouter des rimes dans le standard 🙂

Herb Sutter remercie les participant(e)s. On a un peu débordé du temps alloué

Je me déplace vers la salle destroy_n() pour saluer le très sympathique Sy Brand qui s'apprête à donner une conférence sur la composition (ça risque d'être très bien). Pendant les quelques minutes de pause, j'en profite pour nettoyer les litières des chats. Faut savoir qu'il y en a une dans mon bureau (une sur quatre dans la maison), ce qui constitue un facteur de motivation important pour les garder « propres »...

Petite jasette de quelques minutes avec les gens à ma table (dont Guy Davidson, toujours aussi sympathique), puis ça commence.

Vidéo : https://www.youtube.com/watch?v=AGRWRwi7rD0&feature=youtu.be

Sy Brand – Building an Intuition for Composition

Sy Brand se présente, et se dit mauvais en mathématiques. En progressant dans ses études, qu'au lieu de s'améliorer au fil des ans, sa situation empirait. Sy Brand était intéressé, mais la notation ne lui parlait pas (ça nous fait un autre point en commun), et les articles n'étaient pas nécessairement bien écrits pour ses besoins. Sy Brand dit donc souhaiter offrir le type de présentation que quelqu'un comme lui aurait apprécié

Sy Brand commence par aborder std::accumulate(). Dans sa version par défaut qui fait une somme, comme dans sa déclinaison paramétrée. C'est un Fold. Un algorithme est présenté, qui réalise une version sans court-circuit de all_of ou de any_of à l'aide d'accumulate. Sy Brand fait remarquer qu'on peut implémenter plusieurs autres algorithmes standards à l'aide d'accumulate, ce qui explique l'arrivée des Fold Expressions dans le langage.

Sy Brand analyse ensuite la signature de accumulate, en ajustant les paramètres (élément identité, fonction binaire). Le cumul à réaliser dépend des deux paramètres pris ensembles. Sy Brand fait remarquer que répartir le calcul sur plusieurs coeurs permet de répartir l'élément identité sur ces coeurs (faut que l'opérateur binaire soit associatif pour que ça fonctionne).

Sy Brand décrit plus en détail accumulate, dont les propriétés décrivent en fait un monoïde. Les monoïdes ouvrent la porte au parallélisme.

Sy Brand aborde la question de composer des critères de tri pour faire un tri multicritères, et son API est franchement charmante. Il montre qu'on peut composer les critères constituant des monoïdes avec des Fold Expressions

Sy Brand salue le travail de Ben Deane au passage. La foule fait de même dans le clavardage 🙂

Sy Brand aborde ensuite la question de transform(), et montre comment transformer un vector<cat> en vector<cute_cat>. La même idée est illustrée avec des optional<cat>, puis en combinant des futures avec des continuations. Sy Brand montre que transform est un Map ou un Fmap. L'opération est un foncteur au sens de la théorie des catégories

Sy Brand présente des « lois des foncteurs ». Une fonction identité devrait préserver l'objet qui lui est passé en paramètre. Appliquer deux transformations en séquence devrait équivaloir à appliquer la composition des transformations.

Sy Brand fait remarquer que The Standard Template Library de Stepanov et Lee (1994, Hewlett Packard) exposait les itérateurs à titre d'idée clé. Les intervalles de C++ permettent d'exposer des foncteurs au sens de la théorie des catégories

Sy Brand aborde ensuite des opérations importantes des Ranges, particulièrement transform, join (pour transformer des optional<optional<T>> en optional<T>) qu'il suggère de réécrire and_then() pour combiner join et transform (un Bind)

Sy Brand revient sur les futures. Avec un and_then, les continuations sont aussi naturelles que le passage d'optionnels.

Autre exemple, les processeurs de langages, que Sy Brand représente comme des fonctions de string vers string. Une notation à la Lisp (tête, queue) est présentée, puis Sy Brand montre une approche de combinaison. C'est très chouette comme code

Sy Brand passe aux monades (ça réagit), qu'il associe au marshalling de données dans / hors d'un contexte. Les coroutines sont présentées comme se prêtant aux monades, se basant sur un exemple de Gor Nishanov consommant des données d'un lien TCP. C'est un cas où and_then échoue, du moins dans le cas synchrone. Avec co_await, le code séquentiel devient asynchrone avec un soupçon de décoration, tout en conservant la simplicité du code original. Les coroutines permettent de profiter naturellement du caractère monadique des opérations asynchrones

Sy Brand parle ensuite des exceptions statiques de HS. L'impact d'une mention throws dans la transformation du type de retour (de int à expected<int,error>, essentiellement) est expliqué. Ce mécanisme expose en quelque sorte la facette monadique du traitement d'erreurs

Sy Brand suggère de chercher les monoïdes, les monades et les foncteurs dans le code que l'on écrit.

Q : Do we need different overloads of the pipe operator to compose different types of functions differently, or are these slides using the auto-based overload you wrote at the beginning?

Sy Brand : oui. Il faut tester pour la présence ou l'absence de valeur dans un optional<T>, ou fusionner deux vecteurs...

Q : What are some frequent use cases for fold expressions?

Sy Brand : je m'en sers beaucoup avec operator,() personnellement

Q : Is the programming definition of monad equivalent to the mathematical definition? And how does all that relates to the biblical/philosophical definition of monad?

Sy Brand : la définition en programmation fonctionnelle dérive de celle de la théorie des catégories. Le mapping est presque direct; même en Haskell, il y a de petits trous

Q : Could you explain the difference between a monoid and a monad?

Sy Brand : l'un est un triplet, permettant des Fold et du parallélisme; l'autre est un and_then, et permet de composer dans une sorte de pipeline

Q : Do you think it would be useful to have vocabulary types for monoids, monads... in C++? A vocabulary "transform", "and_then"? Is that even possible?

Sy Brand : c'est pas évident; faudrait un moyen de spécialiser certains traits. Ça se fait, cela dit, et il y a des propositions en ce sens

Q : do you find it confusing when things (like coroutines) are close to monoids but don't quite meet all the requirements?

Sy Brand : on parle bien de monades, pas de monoïdes... Oui, c'est embêtant.

Q : Is throws like Either monad?

Sy Brand : absolument. C'est la même chose que expected<T,E> aussi

Q : Do you have any plans to propose your implementation of tl::expected to the standard?

Sy Brand : j'ai une implémentation, mais je ne sais pas si ça va passer

Q : What is your favourite monad?

Sy Brand : la première qui m'a allumé est le Write Monad

Q : Do you think it's worth striving for pure functional programming in C++, or would you suggest using functional programming concepts to augment the typical imperative style?

Sy Brand : ça dépend du contexte, des contraintes, du comportement de nos types, du contrôle que l'on a sur la base de code à notre disposition... Faut pas être dogmatique, ça finit par être triste (la programmation fonctionnelle finit par faire beaucoup de copies du fait que les objets y sont immuables)

Q : Have developers already done the work of checking whether a specific type follows the "laws" of monads or monoids you laid out / eluded to using type traits, or is such a thing not possible afayk?

Sy Brand : je ne pense pas que ce soit généralement possible en C++. Entre autres, les concepts comme la commutativité et l'associativité ne sont pas immédiatement testables dans le code

Q : Do you think that coroutines could be expanded in a backwards-compatible way so that they would be equivalent (or as expressive as) do-notation?

Sy Brand : je n'y ai pas réfléchi. Intuitivement, si nous avions accès aux sous-fonctions générées par le compilateur, peut-être, mais je ne sais pas si ce serait généralisable

Q : given you reference many interesting libraries, how do you know if you can trust they are high quality / going to be maintained?

Sy Brand : c'est une question sociologique.

Q : In the code examples, was ` | and_then` for the optional some thirdparty library? If it was, where can we find it?

Sy Brand : je pense l'avoir pris d'une bibliothèque de Vittorio Romeo

Je suis resté un peu après pour bavarder avec Sy Brand, Guy Davidson et Paul Licameli, avec qui j'ai échangé par la suite par courriel car il avait des questions sur la réflexivité statique.

Vidéo : https://www.youtube.com/watch?v=FRkJCvHWdwQ

Marc Gregoire – C++20: An (Almost) Complete Overview

Marc Gregoire se présente, et annonce que C++ 20 est officiellement adopté. Il parlera des quatre plus gros morceaux (modules, Ranges, coroutines, concepts) et parle d'une liste (plusieurs dizaines) de nouveaux mécanismes et outils

Marc Gregoire y va de nouveaux mots clés (il y en a huit!) : concept, requires, constinit, consteval, co_await, co_return, co_yield et char8_t. Il y a aussi deux nouveaux identifiants contextuels : import et module

Marc Gregoire présente les modules et leur rôle. La séparation entre interface et implémentation est expliquée, et il en va de même pour la séparation en sous-modules et en partitions. Surtout, les macros seront de meilleurs citoyens du système désormais (Marc Gregoire présente un exemple avec des fonctions dont le type de retour est auto). La transition permettant d'importer un en-tête standard (pas nécessairement un en-tête maison) est présentée

Marc Gregoire décrit les Ranges comme une séquence d'éléments. Ils ne remplacent pas totalement les paires d'itérateurs, mais rendent plusieurs cas de figure plus élégants (et moins risqués, évitant les paires d'itérateurs mal appariées). Les adaptateurs et leurs avantages sont mis de l'avant

Marc Gregoire fait un bref tour des concepts-clés des Ranges (algorithmes, projections, Views, fabriques, pipelining). Il montre que les types peuvent être transformés en cours de pipeline, et mentionne que le tout est fait d'évaluations paresseuses jusqu'au moment d'évaluer le résultat

Marc Gregoire passe aux coroutines, des fonctions asynchrones résumables. La machinerie est là, mais les classes chouettes qui en profiteront ne sont pas encore standards (p. ex. : on n'a pas de std::generator<T> pour le moment).

Marc Gregoire présente les concepts comme des prédicats statiques sur des types, et donne des exemples. Il en profite pour montrer requires au passage. Il construit un exemple exigeant un T::swap(T&) qui soit noexcept et un T::size() qui soit de type std::size_t. Marc Gregoire présente quelques-uns des concepts standards, et montre en quoi les concepts améliorent significativement la qualité des diagnostics

Marc Gregoire enchaîne avec les améliorations apportées aux λ : capture de this, contraintes sur les types (ça allège l'écriture, mais ses exemples ne sont pas les meilleurs), un raffinement aux init-captures avec ellipses...

Marc Gregoire explique les raffinements à constexpr : accepte les méthodes virtuelles, blocs try... catch locaux, new et delete globaux et locaux, dynamic_cast... Ceci permet d'avoir des string et des vector qui soient constexpr

Pour la concurrence, Marc Gregoire mentionne que shared_ptr<T> est Thread-Safe pour ce qui est du compteur de références, mais pas pour les éléments pointés, alors que C++ 20 a des atomic<shared_ptr<T>>

Marc Gregoire enchaîne avec jthread qui joint sur destruction, et l'annulation collaborative (stop_token, stop_source, stop_callback). Il compare un exemple avec thread et son équivalent avec jthread (chic simplification)

Quelques nouvelles primitives de synchronisation suivent : semaphore, latch, barrier. Marc Gregoire explique qu'il est maintenant permis d'attendre (wait, notify_one et notify_all) sur un atomic, et que nous avons des atomic_reference

Marc Gregoire poursuit avec les trucs plus mineurs :

Marc Gregoire liste ensuite plusieurs ajouts mineurs de la bibliothèque (starts_with() et ends_with() pour les string et les string_view; contains() pour les conteneurs associatifs, etc.)

Enfin, Marc Gregoire présente lerp() et midpoint() qui seront bien utiles pour plusieurs de mes étudiantes et de mes étudiants

Il y avait 32 questions posées par le public, mais il y a eu coupure brusque pour la musique. Cette partie du colloque n'est pas tout à faire au point...

Je me dirige vers Embedded pour la prochaine présentation. Je profite de la pause pour mettre un peu à jour ce journal...

Vidéo : https://www.youtube.com/watch?v=gzqLScDUlDI

Ben Saks – Embedded: Customizing Dynamic Memory Management in C++

Ben Saks se présente sommairement, puis va dans le vif du sujet, mentionnant qu'une partie de ce qui suivra s'applique aussi hors du domaine des systèmes embarqués

Ben Saks dit savoir que plusieurs systèmes embarqués n'ont tout simplement pas recours à l'allocation dynamique de mémoire, pour plusieurs raisons (trop lent, non-déterministe, fragmente la mémoire, etc.), mais il s'avère que C++ offre des mécanismes paramétrables qui permettent de contourner ou d'éliminer ces irritants

Ben Saks parle de durée de vie (storage duration), qu'elle soit statique, automatique ou dynamique. C'est de cette dernière qu'il est question aujourd'hui.

Il commence en présentant malloc() et free(). Il ne parle toutefois pas du comportement lors d'un échec, et il ne présente pas les signatures. Il parle toutefois de la présence de constructeurs, qui distingue C et C++ (new est un processus en deux temps : allouer puis initialiser). Il réutilise l'exemple de Dan Saks la veille, puis fait une présentation analogue pour delete. C'est quand même pas mal comme présentation. Il note qu'on ne peut pas appeler explicitement le constructeur à travers un pointeur, mais on peut appeler le destructeur explicitement

Ben Saks présente les new-expressions à l'aide de l'opérateur new. Il s'attarde à la signature globale en premier lieu. Il fait de même pour les delete-expressions et l'opérateur delete

Ben Saks note que par défaut, le comportement de new et de delete risque de ressembler à celui de malloc() et de free(), ce qui explique l'intérêt de les implémenter soi-même pour un système embarqué.

Le requis de lever bad_alloc dans new si l'on ne parvient pas à réaliser la postcondition est un irritant pour les systèmes embarqués...

Ben Saks donne un exemple semblable à celui que j'utilise pour comptabiliser la mémoire allouée, à titre d'exemple. Sa version utilise une statique globale non-synchronisée par contre, et compte le nombre d'allocations et de déallocations, pas le nombre de bytes

Ben Saks présente sommairement la version pour allocations suralignées, mentionnant l'importance de la remplacer aussi si la version plus classique l'est. Il fait aussi un survol des versions avec taille de delete

Ben Saks suggère qu'il soit souvent suffisant, dans un système embarqué, de se limiter à des versions méthodes des opérateurs d'allocation. C'est plus près des besoins de ces systèmes. Il note que ceci permet de l'allocation par blocs de taille fixe (il ne parle pas du problème résultant de classes dérivées héritant de ces fonctions, mais la question vient de la salle et il répond bien; il reçoit plusieurs questions un peu hors-champ, pauvre lui...)

(je dois m'absenter une quinzaine de minutes pour un truc bancaire)

Quand je reviens, Ben Saks aborde les versions no-throw de new et de delete, et explique pourquoi la version de delete est nécessaire

Ben Saks conclut avec un retour sur la question. C'est pas mal finalement

Ben Saks a pris la plupart de ses questions pendant l'exposé, alors il n'y a pas vraiment de questions à la fin. Pour les quelques-unes qu'il y a, je vois qu'il a discuté de blocs correctement alignés avec un union contenant un char[] aligné comme un T et un pointeur au prochain bloc

Je migre vers generate_n() pour voir le toujours divertissant Stephan T. Lavavej. J'ai attrapé l'AMA de Tanki Zhang mais, n'ayant pas assisté à sa présentation, il me manquait des bribes pour bien suivre les échanges.

Vidéo : https://www.youtube.com/watch?v=8kjRx8vo6y4&feature=youtu.be

Stephan T. Lavavej – C++ STL Features: One Year of Development on Github

Stephan T. Lavavej parle très vite et a une pensée très structurée, très précise. Il faut être alerte pour suivre son discours. D'ailleurs, il nous manque les premières secondes quand la vidéo apparaît.

Stephan T. Lavavej dit qu'il y aura trois parties à sa présentation : 0 qui sera un survol de la dernière année, 1 qui listera les éléments de C++ 20 maintenant disponibles, et 2 qui sera un réflexion sur leur nouveau processus de développement à travers GitHub

Pour 0, Stephan T. Lavavej rappelle que Microsoft est passé à un modèle à code ouvert l'an passé, selon une licence Apache avec exception LLVM pour faciliter les échanges. Ils ont eu beaucoup de contributions externes, et de très bonne qualité. Stephan T. Lavavej dit qu'ils visent toujours C++ 20 en 2020 (cool!); en date d'aujourd'hui, il en reste 23 à implémenter

On passe à 1. Stephan T. Lavavej présente d'abord les conversions arithmétiques habituelles (j'aime sa maniere de montrer les inclusions et main en tout petit!), héritées de C qui font des trucs... surprenants à l'occasion. Une fonction cmp_less() que je ne connaissais pas fait quelque chose de plus raisonnable avec des entiers. Il y a une famille de ce genre, incluant in_range() qui touche à mes cours

Stephan T. Lavavej indique que ces fonctions, de même que plusieurs autres, sont constexpr. Il y en a vraiment beaucoup, particulièrement dans <algorithm> et <numeric>, mais aussi dans <complex>. Certains profitent de std::is_constant_evaluated(). Stephan T. Lavavej explique que même les algorithmes Run-Time en profitent, par exemple pour des Lookup Tables utiles pour optimiser des algorithmes à l'interne. Il donne un exemple qui bénéficie d'un std::is_sorted constexpr avec un tableau de string_view

Stephan T. Lavavej poursuit avec les nouvelles fonctions pour éliminer des éléments comme std::erase() et std::erase_if() avec explications très claires et exemples

Ensuite, Stephan T. Lavavej présente atomic_ref<T> et les différences avec atomic<T>. Un atomic_ref<T> n'entrepose pas le T, ce qui peut être avantageux si une variable est accédée de manière séquentielle pour un temps, puis de manière concurrente à un autre moment (mais pas les deux en même temps, par définition), question de ne pas payer les coûts quand ça n'apporte rien de plus. Les interfaces des atomic<T> et des atomic_ref<T> sont identiques

Pour terminer les nouveaux mécanismes présentés, Stephan T. Lavavej procède avec span<T>, tout léger et tout efficace. Stephan T. Lavavej le présente comme une paire {T*,longueur}, mais en mieux. Les constructeurs ont été écrits avec beaucoup de soin; entre autres, ils évitent la covariance incorrecte et dangereuse sur les tableaux qu'on trouve en C# ou en Java. La version Debug de leur implémentation valide les bornes, mais la version Release évite ces coûts. Un exemple d'appel montre qu'une fonction prenant un span<const int> peut accepter un int(&)[N], un array<int,N> ou un vector<int> sans coûts. Stephan T. Lavavej en profite pour distinguer contiguous et random-access, montrant pourquoi deque<T> ne passserait pas la rampe

Stephan T. Lavavej survole quelques autres trucs récents (atomic<shared_ptr<T>> et atomic<weak_ptr<T>>, <bit>, midpoint(), lerp(), <numbers>). Chouette!

Pour 2, Stephan T. Lavavej parle du processus de migration d'un modèle propriétaire à un modèle à code ouvert sur GitHub. Ils utilisent un historique linéaire avec quelques Feature Branches de courte durée de vie quand les mécanismes sont gros. Ils utilisent les Issues pour fins de suivi du développement, pas seulement pour les bogues.

Pour fins d'intégration continue, ils utilisent des Azure Pipelines. Pour fins de présentation, ils utilisent clang-format qui leur sauve un temps fou.

Stephan T. Lavavej dit qu'ils utilisent les Projects de GitHub, et qu'ils tiennent un Changelog à jour sur le Wiki de leur site. Enfin, ils ont un Status Chart pour présenter visuellement la progression de cette démarche

Stephan T. Lavavej parle ensuite des outils, mais c'est moins mon truc. Truc amusant : leurs fonctions mathématiques spéciales utilisent Boost.Math. Autre truc amusant : ils utilisent CMake avec Ninja, pas MSBuild

Stephan T. Lavavej relate quelques anecdotes amusantes, dont une qui résolvait un bogue de 43 ans avec une solution de 40 ans. Le bogue provenait d'un article dont Donald E. Knuth était l'un des co-auteurs.

Stephan T. Lavavej explique la philosophie mise en application pour les revues de code, stratégie influencée directement par ce que dicte le standard. Le code de leur bibliothèque semble écrit par un seul et même auteur

Q : Why isn't constexpr implicit added by the compiler to any function when suitable? Is there a downside to it?

Stephan T. Lavavej : la raison est que constexpr est une garantie que l'on ne fera jamais quoi que ce soit qui pourrait empêcher constexpr (logging, reinterpret_cast, etc.)

Q : is erase_if similar in complexity to calling remove_if then erase?

Stephan T. Lavavej : oui. Pour vector, c'est implémenté comme ça, mais ça dépend du conteneur. Toutes les versions sont de complexité linéaire

Q : What's the next big C++ thing Microsoft is going to open source?

Stephan T. Lavavej : pas sûr. Peut-être le Runtime de VisualC++

Q : What is the motivation for the people contributing to your GitHub project? Is there any incentive to do so or are these people just lovely enthusiasts?

Stephan T. Lavavej : je suppose que c'est améliorer C++ et contribuer à un chouette projet

Q : does the array have to be static for ranges::is_sorted to work?

Stephan T. Lavavej : il faut que le tableau soit constexpr mais pas nécessairement static

Q : What were the downsides of moving to open source?

Stephan T. Lavavej : ça a pris du temps et de l'énergie. Faut aussi dupliquer les changements du dépôt GitHub au dépôt de production. On s'y attendait. Ça va très bien

Q : Is constexpr available on parallel algorithms?

Stephan T. Lavavej : non, pas en C++ 20

Q : Why is passing by value faster for small types like span? When do we decide a type is not small enough?

Stephan T. Lavavej : c'est une paire de primitifs. En général, quand on est jusqu'à la taille de deux primitifs, le passage par valeur est préférable, grosso modo

Très intéressant tout ça. Je ne pourrai pas faire les Lightning Talks, car je dois aller chercher Ludo à l'école et m'occuper du souper...

Jour 3 16 septembre

Ce sera une grosse journée aujourd'hui, car en plus du colloque, j'ai un rendez-vous en lien avec la santé dans ma famille, et je devrai manquer les dernières conférences (qui semblent très intéressantes). Heureusement que le tout sera rendu public dans quelques semaines!

Ma journée débute dans la pièce count_if() pour un AMA avec Bjarne Stroustrup, animé par Herb Sutter.

Bjarne Stroustrup AMA

Herb Sutter explique la procédure pour ce matin, et Bjarne Stroustrup semble d'excellente humeur.

Q : comment votre bibliothèque de lundi matin gère-t-elle l'ordre des bytes dans un entier?

Bjarne Stroustrup : on n'en tient pas compte, présumant une homogénéité chez les deux homologues, ce qui est notre cas d'utilisation. Nous y porterons attention quand le domaine le demandera.

Q : si tu pouvais recommencer C++ de zéro, que changerais-tu?

Bjarne Stroustrup : c'est une question qui revient souvent. Du point de vue du langage, les morceaux les plus importants sont corrects. Je suis content que l'on ait enfin les modules et les coroutines. J'aime les exceptions, mais je porterais plus attention à l'implémentation. Il y aurait encore RAII et on ne toucherait pas à la collecte d'ordures. Nous avons réussi le portrait général. Les concepts, si je les avais compris à l'époque, auraient été là dès le début. Peut-être que je porterais plus fortement attention aux éditeurs de liens et aux Package Managers.

Q : dans votre bibliothèque, pourquoi utiliser char et non-pas std::byte? Aussi, pourquoi un Span maison plutôt que std::span?

Bjarne Stroustrup : pour char, c'est une question d'habitude. Je vais passer à std::byte sous peu. Pour Span, j'ai deux enjeux : je veux une stratégie particulière de traitement d'erreurs, et j'ai besoin à la fois de Span et de Span_ref. Je n'exclus pas de passer à std::span éventuellement, cela dit.

Q : que faites-vous dans votre travail chez Morgan Stanley?

Bjarne Stroustrup : c'est diversifié. Je représente C++, je fais des AMA, des conférences, je fais beaucoup de travail pour le comité de standardisation. Je parle aux gens, je teste mes idées dans la communauté. J'essaie de comprendre le monde et de ne pas me retrouver coincé dans une bulle. J'enseigne baucoup. Je programme un peu. J'essaie de voir ce qui est nécessaire et ce qui est superflu.

Q : quel est votre livre préféré de C++ qui ne soit pas écrit par Bjarne Stroustrup?

Bjarne Stroustrup : je ne suis pas à l'aise de répondre à cette question...

Q : est-ce que Rust, D, Swift... sont des compétiteurs ou de chics voisins?

Bjarne Stroustrup : je ne pense pas beaucoup aux autres langages. Je regarde ce qu'ils font, mais j'évite les fanatiques de tous les langages, incluant C++. Je n'aime pas l'obscurantisme. J'aime bien Rust qui profite de RAII et ne dépend pas de la collecte d'ordures. Il y a tellement de langages... Java ne permet pas de résoudre les problèmes qui m'intéressent; c'est un bon langage mais ce n'est pas le langage que j'aurais conçu

Q : quand aura-t-on operator.()? J'en ai besoin!

Bjarne Stroustrup : on pensait l'avoir pour C++ 17, mais mon approche reposant sur les conversions implicites n'a pas passé et j'ai été occupé par la suite. Faudrait que je m'y remettre

Q : quel est le futur du livre The C++ Programming Language?

Bjarne Stroustrup : grosse question. Ça prendrait plusieurs années à mettre à jour, et est-ce que ce serait le meilleur usage de mon temps? On m'a suggéré de n'écrire que la partie langage, pas la partie bibliothèque, mais ça ne me semble pas approprié. C'est un livre de 1400 pages; je vais peut-être écrire un livre de 200 pages pour démarrer les gens. Je vais peut-être revisiter Programming, Principles and Practice Using C++ pour C++ 20, mais c'est embêtant car plusieurs étudiant(e)s n'ont pas accès à des compilateurs à jour. Il y a des liens entre l'enseignement, la GSL, les outils...

Q : dans Flats, comment l'encodage des chaînes de caractères est-il pris en charge?

Bjarne Stroustrup : je suppose un encodage homogène des deux homologues pour le moment. Si je supporte divers encodages, je vais avoir à ajouter des constructeurs.

Q : pouvez-vous comparer les types de Flat et les TLV?

Bjarne Stroustrup : je suis resté au minimum pour sauvegarder des nanosecondes. C'est par les Views que ... (le son est mauvais, j'en manque des bouts)

Q : pourriez-vous faire une présentation de trois heures sur le code de Flats dans le détail?

Bjarne Stroustrup : c'est une idée splendide. Peut-être au printemps.

Q : avez-vous un exemple d'utilisation surpenante de C++?

Bjarne Stroustrup : réaliser que des centaines ou des milliers de personnes travaillent ensemble sur une même base de code me ravit. Ce que Google fait est surprenant; les montres intelligentes aussi, mais moins car C++ convient tout à fait à ce type de problème. Le Human Genome Project, le collisionneur d'hadrons... Le monde a tellement changé depuis que j'ai créé C++; le monde est surprenant!

Q : comment pourrions-nous aider à l'adoption des exceptions?

Bjarne Stroustrup : on pourrait améliorer les implémentations. On pourrait mieux les intégrer aux bibliothèques à liens dynamiques. On pourrait aider au débogage en facilitant la navigation de la pile d'appels. Il faut surtout expliquer que ce n'est pas un Either/ Or; il y a plusieurs mécanismes de traitement d'erreurs, et les forces et les faiblesses de chacun varient. Les exceptions sont avec nous depuis une trentaine d'années et mènent à du meilleur code que les codes d'erreurs. Entre autres, il y a une différence entre du code rapportant une erreur vers l'appelant immédiat et du code rapportant une erreur à travers plusieurs niveaux d'appels

Q : vous avez dit regretter de ne pas assez utiliser les concepts avec Flats. Pouvez-vous élaborer?

Bjarne Stroustrup : c'est une erreur de ma part, et ça prouve que je n'ai pas suffisamment réfléchi au problème au préalable. Pensant que je n'en aurais pas besoin, je me suis ramassé à gérer des bogues inutiles. Si vous avez du code générique, vous voulez des concepts

Q : comment apprendre C++ plus rapidement?

Bjarne Stroustrup : beaucoup d'enseignement de C++ est mal fait; enseigner C d'abord est une erreur. Penser qu'il faut des hiérarchies de classes à tout prix est une erreur. Vous pouvez prendre mon livre A Tour of C++ pour débuter. Quand je vois new dans du code client, je sais que ça va mal aller : le code néglige RAII et s'empêtre dans les détails. L'éducation seule ne suffit pas; c'est pourquoi nous avons besoin de la GSL, et de meilleurs outils. Je note des critiques sur le code de Flats présenté lundi, disant que ça ne passerait pas une revue de code... C'était du code généré automatiquement! Mais j'ai vérifié le générateur 🙂 J'ai fortement confiance en l'analyse statique

Q : à propos de UFCS, qui semble être le seul mécanisme de D&E manquant en C++ 20. Le souhaitez-vous toujours?

Bjarne Stroustrup : je suis fortement en faveur de UFCS. Je suis fatigué de mener ce combat; j'en suis plein d'ecchymoses. Je ne sais pas si les adversaires ont changé d'avis, mais je l'espère. Notez que D&E souhaite aussi operator.() et j'ai plus confiance de ce côté car j'ai de nouveaux arguments

Q : allez-vous mettre D&E à jour?

Bjarne Stroustrup : non, je n'ai pas le temps, mais mon texte pour HOPL poursuit D&E en quelque sorte

Q : restez-vous en contact avec Alexander Stepanov? Que pense-t-il de C++ 20?

Bjarne Stroustrup : je reste en contact avec lui, et il est à la retraite. Il ne souhaite plus parler de programmation. C'est un très charmant personnage. Parler code avec lui à ce stade serait lui manquer de politesse.

Q : pensez-vous à la retraite?

Bjarne Stroustrup : pas pour le moment. J'ai encore le feu sacré. Je me demande parfois si prendre ma retraite me donnerait plus de temps pour mener mes projets à terme, mais ce n'est pas mon plan pour l'instant. Je dois avouer avoir trop de télérencontres pour le moment

Q : allons-nous un jour nous débarrasser de comportement indéfini?

Bjarne Stroustrup : GDR mène un groupe en ce sens, mais le comportement indéfini est mal compris. Le compilateur ne s'objectera pas à du code source légal. Pensez à un débordement sur un entier signé; la présence de comportement indéfini ouvre la porte à de meilleurs diagnostics de la part des vendeurs de compilateurs. Dans Flats, quand le code sera disponible, vous constaterez d'ailleurs beaucoup de validation de débordements

Q : quel est l'impact de constexpr sur le comportement indéfini? Et sur le code Safety-Critical?

Bjarne Stroustrup : constexpr nous donne en quelque sorte une forme de fonction pure, ce qui nous donne une plus grande sécurité. GDR et moi savions ce que nous faisions en proposant cela. Le code C++ moderne, particulièrement avec le soutien de la GSL, est très sécuritaire. Je suis certain que l'on ne peut pas retirer les trucs plus rugueux de C++ (arithmétique de pointeurs, arithmétique combinant les entiers signés et non-signés, manipulation de bits); ce qu'on fait est d'ajouter des bibliothèques qui utilisent bien ces mécanismes, et encourager le recours aux outils de ces bibliothèques qui, eux, seront vérifiables statiquement

Q : bien que j'aime C++ personnellement, ma fille a suivi un cours de Java et par la suite, je lui ai conseillé Python. Que conseilleriez-vous?

Bjarne Stroustrup : ça dépend de l'âge. On peut très bien apprendre C++ vers dix ans. Le plus gros irritant est le Toolchain : installer une nouvelle bibliothèque est trop compliqué. Avec des étudiant(e)s plus avancé(e)s, C++ devient important : nous dépendons de logiciels critiques, qui répondent à temps. Nous avons besoin de professionnels. Les gens dont ma vie dépend, je souhaite que ce soient des professionnels compétents.

(la connexion a coupé à trois minutes de la fin...)

J'aime bien Bjarne Stroustrup; c'est quelqu'un que j'ai appris à connaître depuis 2015, et avec qui j'ai des relations fort agréables. Il réfléchit, fait preuve de douceur, et a généralement de l'écoute même s'il a des positions bien campées.

Des amis sur Twitter me mentionnent que Jody Hagins a donné une bonne conférence hier. Je suis content : c'était un des participants dans mon cours à CppCon 2016, et c'est un très chic type.

Je me dirige ensuite vers la pièce generate_n() pour une présentation de Borislav Stanimirov, qui était venu à ma rencontre lors de CppCon 2019 suivant ma présentation sur l'adéquation de C++ en tant que premier langage. Il souhaitait m'exprimer (gentiment) son désaccord sur la base d'idées exprimées dans son blogue quelques mois plus tôt. J'avais lu le tout à l'époque mais ça ne me semblait pas frapper la cible annoncée, alors j'avais mis de côté. Cependant, puisqu'il a pris la peine de venir à ma rencontre, j'ai relu ce blogue par la suite (quelques mois plus tard, à cause du tourbillon de la pandémie), prenant soin d'y aller dans le détail, et je lui ai écrit pour lui expliquer mon point de vue (en gros, ses critiques sont selon moi pertinentes pour C++, mais pas pour C++ en tant que langage pour débutants). Si vous voulez vous faire une tête, le blogue en question est Stop Using C++... as a First Language

Vidéo : https://www.youtube.com/watch?v=ZSrIZW2Hzhk&feature=youtu.be

Borislav Stanimirov – No Touchy! A Case Study of Software Architecture with Immutable Objects

Borislav Stanimirov se présente sommairement, puis présente le logiciel sur lequel il travaille (pour le traitement de patient(e)s atteint(e)s de cancer). Il fait une petite démonstration devant nous en montrant comment le logiciel détecte des tumeurs probables sur une machine a 64 coeurs (mais il l'exécute sur son ordinateur portatif, alors c'est moins fluide).

Borislav Stanimirov explique que le logiciel (quand même sophistiqué) a été réécrit à partir de rien en février 2019. L'affichage est dans un fureteur, et le back-end est en C++ 17. Le serveur d'application expose des services qui reposent sur des sessions. Des Workers à courte durée de vie font les traitements.

Le service d'interface personne/ machine et le service Web échangent du JSON. Le service de traitement représente un traitement en cours (Borislav Stanimirovv passe vite sur les diapos).

Les services manipulent des objets, mais il y a beaucoup de fils d'exécution et de processus, alors beaucoup d'accès concurrents.  C++ 17 offre des shared_mutex (Borislav Stanimirov montre une implémentation qui les utiliserait). Dans son code, les Writers doivent attendre après les Readers, pas le contraire. Ils ont envisagé un CoW à cet effet, mais dans le contexte d'utilisation qu'il présente, c'est inapproprié (dans son code, il y a encore des conditions de course)

(en cours de présentation, Borislav Stanimirov s'aperçoit qu'il n'a pas la bonne version de ses diapos... Pas cool pour lui)

Borislav Stanimirov poursuit avec son design, mais CoW et la concurrence, c'est pas terrible, on le sait depuis longtemps. Il arrive éventuellement à des objets immuables.

Borislav Stanimirov utilise string_view à titre d'exemple d'objet immuable (ce sont plus des vues immuables que des objets immuables). Il utilise une méthode detach() pour réaliser un CoW sur demande et réduire le verrouillage

Borislav Stanimirov en arrive au constat que leur implémentation ressemble beaucoup à React.js, qu'il présente très sommairement par la suite. Il décrit les états d'une session d'imagerie par du JSON et montre comment les modifier et provoquer les ajustements à la présentation. Il utilise la réflexivité en JavaScript pour exposer ses idées. Il explique que React.js réalise du Shallow CoW

Borislav Stanimirov revient à C++. Il montre qu'on peut profiter des Workers pour améliorer le design. Il mentionne aussi que cette approche facilite la réalisation de tests d'intégration

 Borislav Stanimirov dit que si les états d'une application sont dans un seul objet, tout ce que fait l'application est une fonction pure, ce qui est éminennement testable. Il y a quelque chose d'intéressant ici... Les Mocks sont triviaux à écrire, le Fuzzing est simple, et récupérer d'un plantage est simplifié. Il est même possible de faire du débogage avec voyage dans le temps

Borislav Stanimirov revient sur son implémentation et apporte des raffinements. Toutefois, quand il revient à son CoW, les objets immuables impliquent des copies de taille considérable. Il frappe un stade où son recours aux indirections revient le mordre...

Borislav Stanimirov dit avoir résolu certains de ses problèmes avec une bibliothèque de son cru nommée Kuzco. Il constate avoir beaucoup, beaucoup d'allocations. Il dit contempler avoir recours à des allocateurs, ou réécrire shared_ptr pour éviter le surcoût de weak_ptr dont il n'a pas besoin

Borislav Stanimirov : nos objets sont immuables, ref-counted, shallow copies and compares (il va trop vite, je n'ai pas tout noté; c'était la dernière diapo de la partie 1)

Borislav Stanimirov poursuit avec ce qu'il nomme des Actions, pour modifier les états. Il note qu'une difficulté de son approche est qu'il devient impossible de valider un état sans tout valider. Il utilise des State Guards, mais je n'ai pas le temps de voir les détails. Je note que son RunGuards(const State&) est void... (pas sûr du const). Ses Guards sont des fonctions presque pures; ce presque complique la mémoisation.

Borislav Stanimirov décrit une démarche de traduction de code déclaratif vers du code impératif, mais son pseudocode est suspect (il utilise une future de manière synchrone, la lançant puis l'attendant...). Je ne suis pas certain de voir où il s'en va... Il en arrive à des Workers nommés, retrouvables, et qui ne se limitent pas à un std::thread

(j'ai manqué la fin pour des raisons... félines)

Je passe à destroy_n() pour entendre l'AMA de Michael Wong et Gordon Brown. C'est déjà débuté à mon arrivée. La technique fait toutefois défaut (c'est plus difficile en général aujourd'hui) et je me redirige vers all_of() pour le Keynote de ce matin. J'en profite pour prendre des nouvelles de Jody Hagins.

Ce Keynote sera donné par Emery Berger, que je ne connais pas vraiment. La présentation utilise « Magie noire » à titre de mot clé... La musique du band habituel nous accompagne en attendant que le tout ne commence

Jon Kalb fait ses annonces quotidiennes. Il nous rappelle que presser Pause pendant une présentation nous fera manquer la fin...

Vidéo : https://www.youtube.com/watch?v=koTf7u0v41o&feature=youtu.be

Emery Berger – Performance Matters

Emery Berger commence par un clin d'oeil à Star Wars... et je me souviens soudainement avoir déjà vu une version antérieure de cette présentation. Il décrit un système de découverte de photos de chats (avec des clins d'oeil à Google).

Emery Berger décrit le système et les étapes du traitement de l'application en question. Bien sûr, sous la couverture, c'est clairement du C++ multiprogrammé. Il y a des traitements, de l'intelligence artificielle, des entrées / sorties, etc.

Emery Berger décrit qu'avec les usagers qui s'ajoutent, l'application devient... lente... très lente...

Emery Berger fait un détour vers les années '80, avec des clins d'oeil amusants. Il met en parallèle le concept de lenteur en relation avec le contexte et le passage du temps. Les courbes classiques montrant que, jusqu'à 2003 environ, le matériel accélérait chaque année, ce qui nous permettait d'être un peu paresseux... Aujourd'hui, c'est une autre histoire. La loi de Moore poursuit (il y a toujours plus de transistors par espace aujourd'hui, même si la fin approche), mais Dennard Scaling influence la courbe de vitesse et non, l'accélération des processeurs ne se poursuit plus vraiment.

Emery Berger met de l'avant que la « performance » est plus critique que jamais. Il montre plusieurs saisies d'écrans d'applications pour téléphones intelligents, et toutes indiquent une mise à jour pour améliorer les « performances »

Emery Berger dit souhaiter discuter de Performance Analysis, et de Performance Profilers.

La manière typique de faire une Performance Analysis est décrite, et implique de le refactorisation suivie de tests comparant le comportement des deux versions devant un échantillon de données représentatif. Il procède ensuite à plusieurs exécutions, car une seule n'est pas significative. Emery Berger indique que des gains à ce stade peuvent n'être que ces coïncidences, et qu'une analyse subséquente est nécessaire. Il recommande un article Layout biases measurement, et sur l'impact du lieu du code sur la vitesse d'exécution. Un truc aussi simple que changer l'ordre des fonctions en mémoire en permutant deux fichiers objets à l'édition des liens peut jouer; la taille des variables d'environnement aussi... et la différence peut être plus grande que celle provoquée par le passage de -O0 à -O3

Emery Berger dit que la refactorisation en elle-même peut avoir suffi à jouer sur l'organisation du code de manière à changer le comportement de la Cache! Il discute ensuite des subtilités architecturales (Cache, TLB, Branch Predictor, Branch Target Predictor, Memory Prefetcher, etc.) et de leur impact important sur la vitesse des programmes

Emery Berger indique qu'un programme plus rapide pour ces raisons peut être plus lent pour n'importe quel petit changement dans le code : ajouter un attribut d'instance, mettre une bibliothèque à jour, ajouter un appel à new... Juste changer de dossier avant d'exécuter peut changer une variable d'environnement, et changer la position du code en lien avec les variables d'environnement. C'est fragile...

Emery Berger se questionne sur des manières d'éliminer l'impact de la disposition du code sur la vitesse d'exécution, en randomisant le tout, pour mieux analyser le comportement des progrsammes. Il parle de son équipe de recherche qui a écrit un logiciel nommé Stabilizer qui vise à faire cela. Il discute de ce qui est randomisé (où va le code, le tas, la pile...), et explique que c'est fait pendant l'exécution du programme

Emery Berger présente les courbes générées par son logiciel, et explique comment les comprendre. Il présente le null hypothesis significance testing, qu'il explique. Leur programme randomise tout chaque demi-seconde et évalue la somme des temps sur un certain nombre d'exécutions (une trentaine). Le théorème central-limite est évoqué (ça rappelle des souvenirs!)

Emery Berger dit avoir testé les optimisations générées par LLVM à l'aide de programmes s'exécutant avec Stabilizer pour voir si l'impact est significatif. Son p-value pour maintenir ou rejeter le null-hypothesis est de 5% (1/20). Il note que -O1 fait une grosse différence sur -O0, et que -O2 fait une différence significative en comparaison avec -O1. Pour -O3 par rapport à -O2, c'est vraiment moins clair.

Emery Berger aborde ensuite le problème de mesurer ces optimisations en général, pas juste sur un programme de test. Il suggère une analyse de variance (quelle est la probabilité de mesurer la différence effectivement mesurée?). La p-value est à 26,4% donc un a à peu près 25% de chance d'observer une différence par pure chance!

Emery Berger dit qu'on est au stade où le compilateur ne suffit pas; il faut un profileur. Malheureusement, les profileurs ne sont pas terribles aujourd'hui pour le code parallèle et concurrent. Il recommande de définir un profil causal, mais c'est pas évident à définir : comment obtenir l'information sur les effets de chaque changement?

Emery Berger propose une démarche par laquelle on accélérerait le code section par section indépendamment, pour mesurer les impacts, mais cela serait magique et ne fonctionne pas; au contraire, il suggère de ralentir (!) les éléments d'un système concurrent pour qu'un élément choisi semble accélérer relativement aux autres. Il fait remarquer que dans certains cas, accélérer un élément d'un programme concurrent peut ralentir les autres (par faux-partage, ou en sur-sollicitant les verrous)

Emery Berger revient sur l'application de recherche de chats. Il propose d'identifier des Progress Points, où les requêtes entrent dans le système et où les réponses sortent, pour calculer les impacts de changements sur le débit; où les transactions débutent et se terminent pour mesurer les impacts des changements de code sur la latence (il utilise Little's Law pour calculer la latence)

 Emery Berger présente un profil causal pour un véritable projet. Les accélérations obtenues, ayant passé par un processus de randomisation, sont telles qu'il est possible d'avoir une confiance plus élevée quant à leur valeur. Il montre comment cela permet aussi de détecter des goulots d'étranglement (il rapporte un cas avec une table de hashage, où ils ont pensé que le ralentissement était dû à de la synchronisation alors que c'était plutôt la fonction de hashage qui était nuisible -- changer un + pour un ^ a entraîné un gain de vitesse de 9%.

Emery Berger poursuit avec des découvertes fortuites, par exemple à travers SQLite. C'est écrit en C et il y a des vtbl manuelles dedans. Il montre qu'un appel indirect pour le verrouillage dans cette table est accompagné d'une prise de mutex, et que même si les deux sont relativement rapides, la paire accroît la contention de manière importante. Corriger cela a accéléré le code de 25%.

Q : est-ce que la randomization de l'espace adressable va changer le profil de vitesse d'exécution à chaque exécution?

Emery Berger : on ne randomise que les bits les plus hauts, qui n'influencent pas le hashage réalisé par le matériel

Q : est-ce que les effets s'amortissent sur de gros programmes?

Emery Berger : si c'est CPU-intensive, clairement pas. Nous avons testé sur Memcache-D, qui est énorme, et on voit l'effet très clairement

Q : effets des optimisations matérielles?

Emery Berger : il y a de la variance, mais pas de l'ordre de 40%

Q : pouvons-nous utiliser cette technique pour chercher le Layout optimal?

Emery Berger : oui... et non. Le problème est que chaque petit changement a de grosses conséquences. Si le code ne change jamais et ne dépend d'aucune entrée / sortie, peut-être, mais j'en doute

Q : est-ce limité à LLVM?

Emery Berger : c'est un composant. C'est plus compliqué sur Windows que sur les autres plateformes, mais ça se fait

Q : avez-vous observé l'impact des variables d'environnement sur plusieurs plateformes?

Emery Berger : oui (il donne des exemples)

C'était bien intéressant tout ça.

De retour à la salle Embedded pour quelque chose qui devrait être croustillant... Je vais manquer la fin pour des raisons familiales, mais je pense pouvoir le revoir en soirée (nous avons des liens bruts, apparemment)...

Vidéo : https://www.youtube.com/watch?v=cWkUqK71DZ0&feature=youtu.be

Paul E. McKenney et Hans Boehm – A Relaxed Guide to memory_order_relaxed

Ok, ça va être costaud.

Les opérations atomiques de C++ sont séquentiellement cohérentes, et empêchent l'entrelacement de certaines opérations. Ça peut coûter cher dans certains contextes... et il est souvent possible de l'éviter

PEM dit qu'avec memory_order_relaxed, les opérations sont vraiment peu chères, mais... les compilateurs génèrent des OOTA (Out of Thin Air) et des RFUB (Read from Untaken Branches). En Java, ils essaient de gérer ces détails depuis plus de vingt ans. PEM et d'autres ont un algorithme de décision... qui requiert un humain!

HB explique que OOTA est présumé rare et RFUB est présumé très rare (c'est controversé, mais SG1 penche pour l'accepter)

HB présente leur syntaxe, très légère en comparaison avec le code

Deux exemples d'opérations atomiques sont proposés par HB. L'un est raisonnable, et l'autre montre l'impact d'un hypothétique OOTA. OOTA est très vilain, car cela brise le raisonnement conséquent... du compilateur sur son propre code!

HB explique qu'il est très difficile d'interdire OOTA. Ni Java, ni C11, ni C++ 11 n'y sont parvenus... malgré d'importants efforts. SG1 investigue toujours. HB présente une formulation beaucoup trop vague utilisée pour C++ 20 (il dit qu'on reconnaît le problème... et que c'est pas mal ça). C'est, dans ses propres mots, embarrassant...

HB poursuit avec un RFUB. C'est horrible de voir les conséquences des accès aux atomiques relaxées sur notre capacité de comprendre le texte d'un programme... Ouf!

PEM reprend la parole et nous rappelle que si nous saupoudrons des accès atomiques relaxés sans réfléchir, nous avons ce que nous méritons. Il y a toutefois des applications raisonnées et contrôlées d'atomiques relaxées :

HB dit que ce qui rend ces idiomes sécuritaires ou pas. Du code chargeant une valeur d'une atomique relaxée n'est pas sécuritaire s'il compte que le fait que cette valeur soit correcte par la suite, par exemple en essayant de déterminer la valeur entreposée dans une autre atomique. HB montre un cas de Lazy Idempotent Scalar Initialization qui donne la migraine. Le code qui provoque du comportement indéfini brise tout plein de trucs qui semblent raisonnables au préalable

HB présente un cas de mutex réentrant reposant sur un id atomique de thread propriétaire et un compteur du nombre de verrous. Ça fonctionne, sauf si le code client donne dans le comportement indéfini, dans quel cas...

HB donne quelques autres cas, incluant écrire un moteur de collecte d'ordures pour Java (on a des cas pour lesquels memory_order_relaxed est requis pour aller chercher le genre de vitesse requis)

PEM présente des cas plus raisonnables. Son premier exemple est un Double-Checked Locking sur un booléen atomique servant de marqueur d'initialisation (en plus du mutex). Ça fait du sens : le premier accès est un load() avec acquire, le second (sous l'égide du mutex) est un load() relaxé, et l'initialisation est un store() release

Un autre exemple de PEM est le chargement initial dans un compare_exhange (la valeur initiale de expected)

PEM mentionne que P2055 liste les catégories de façons acceptables de procéder

Plusieurs questions suivent; la plupart se demandent si ça vaut la peine, considérant le niveau de difficulté. La réponse est oui (de beaucoup). Une porte sur memory_order_consume, à savoir comment se porte-t-elle? PEM dit pas terriblement bien, mais certains progrès sont faits (en particulier par JF Bastien). Enfin, HB et PEM rappellent qu'utiliser un état partagé mutable non-atomique est une bien mauvaise idée...

Ouf, costaud mais très intéressant. J'ai regardé la deuxième moitié en soirée, en préparant ma propre présentation pour demain. On reste dans Embedded pour le toujours pertinent Anthony Williams, toujours en soirée... le lendemain matin, en préparant mon propre matériel.

Vidéo : https://www.youtube.com/watch?v=iUKxvEg0zdk&feature=youtu.be

Anthony Williams – Get Off My Thread: Techniques for Moving Work to Background Threads

Anthony Williams s'intéressera aux techniques pour déplacer des tâches du thread courant vers un thread en arrière-plan.

Il pose d'abord la question du « pourquoi » : dans la plupart des applications, un thread principal recevra les événements (interface personne/ machine; traitement des requêtes provenant du réseau), mais c'est rarement là le lieu approprié pour traiter ces événements. On ne veut pas désactiver le traitement des événements parce qu'on est occupé (ce serait un désastre!)

Anthony Williams dit que l'enjeu est de ne pas bloquer le thread principal. Lancer une tâche auxiliaire et en attendre la complétion n'apporte aucun bénéfice. Il définit non-bloquant au sens de pas en attente de l'exécution d'une tâche de longue durée (c'est informel, mais suffisant pour ses besoins). Un verrouillage de mutex lui convient s'il est de courte durée. Une autre définition de non-bloquant pour lui est libre de toute obstruction, au sens où si on suspend tous les threads sauf un à tout moment, ce thread terminera sa tâche (ceci exige des algorithmes lock-free, des allocateurs lock-free, des files de messages, etc.)

Anthony Williams passe ensuite au « comment ». Le plus simple est de lancer un thread par tâche; une alternative est de passer des données à un thread préalablement démarré et s'exécutant en arriêre-plan; on peut aussi soumettre cette tâche à un Thread Pool générique; enfin, on peut soumettre la tâche à un exécuteur spécialisé, par exemple pour qu'elle soit traitée sur le GPU

Anthony Williams présente des mécanismes pour lancer des threads : std::thread, std::jthread, std::async(std::launch::sync, ...), l'API de la plateforme sous-jacente... Ces mécanismes ont tous le même problème : si on lance un thread, on est pris avec les deux options de détacher ou de joindre... Anthony Williams montre en quoi std::thread et std::jthread se ressemblent ici, mais n'offrent pas de moyen standard pour constater que leur tâche est terminée. C'est plus chouette avec std::async() à cause des std::future (faire un wait_for(0s) et tester pour std::future_status_ready), mais ça reste du sondage et ça peut consommer des ressources inutilement

Anthony Williams affirme que lancer un thread pour chaque tâche est une mauvaise idée

Selon Anthony Williams, un thread dédié en arriète plan peut être une idée raisonnable : on le crée initialement; le gestionnaire d'événements reçoit un message; le gestionnaire d'événements soumet la tâche correspondante au thread dédié; le gestionnaire d'événements se rend disponible pour accueillir le prochain événement; ultérieurement (idéalement bientôt), le thread dédié traite le message et se met en attente de la prochaine tâche (retourner le résultat du traitement vers le demandeur sera traité plus tard); éventuellement, le thread dédié est arrêté puis détruit. Les inconvénients sont : le thread vit longtemps et consomme des ressources, qu'il soit actif ou pas; le traitement de l'événement est déconnecté de l'événement en tant que tel, ce qui introduit de la latence; enfin, le traitement des événements est séquentiel, pas parallèle, ce qui peut sous-utiliser le matériel (mais simplifie le raisonnement, faut l'avouer). Si le thread dédié ne communique avec le monde extérieur qu'à travers des messages, il devient facile à tester. Enfin, annuler des tâches non-complétées est trivial (on ferme le thread tout simplement)

Anthony Williams explique que si un seul thread ne convient pas, une alternative est un regroupement de threads (un Thread Pool). Il décrit le modèle. Les bons côtés sont que les tâches sont complètes en elles-mêmes, donc testables; le nombre de threads peut être ajusté en fonction du matériel disponible; les threads ne sont pas dédiés, et peuvent être partagés avec le reste du processus. Les désavantages sont que les tâches sont exécutées dans un ordre arbitraire, en fonction de leur collecte par les Workers (si on n'implémente pas de mécanisme de priorité, évidemment); la gestion des événements est disjointe de leur occurrence; les tâches peuvent être exécutées concurremment, donc il faut porter attention à leurs interactions; l'exécution des tâches peut être ralentie par ce qui se passe ailleurs dans le processus; il est difficile d'annuler les tâches d'une source spécifique.

Le plus gros irritant selon Anthony Williams est que l'ordonnancement est imprévisible, ce qui peut être résolu par des continuations. Si B est une continuation de A, alors B et A ne peuvent être exécutées concurremment. Évidemment, les continuations réduisent la concurrence, et le problème de l'annulation demeure entier.

Anthony Williams aborde ensuite le problème de l'annulation. Cet enjeu compte surtout quand des événements subséquents demandent de terminer des événements antécédents; on ne veut pas de Dangling Tasks. Utiliser un stop_token de C++ 20 fait le travail. Une demande d'arrêt ne signifie pas un arrêt immédiat; le processus est collaboratif. Il suggère de compter les tâches qui se terminent (mais pas dans le thread principal) avant de finaliser le traitement, et donne des exemples de code pour y arriver.

Pour ce qui a trait au suivi de la progression, Anthony Williams suggère de provoquer des événements sur le thread principal (note : je ne suis pas d'accord, mais je comprends pourquoi il le fait... Disons qu'il vaut mieux rendre la mécanique transparente).

Anthony Williams passe ensuite aux coroutines. Elles sont merveilleuses, mais elles ne sont pas magiques. Elles peuvent simplifier le code et en faciliter l'entretien. (il donne un exemple; le code semble impératif et séquentiel)

Anthony Williams finit en proposant quelques consignes : on veut des threads qui répondent aux requêtes (le reste est un rappel de la présentation)

Q : peut-on tuer un thread?

Anthony Williams : tu peux, mais c'est une mauvaise idée parce que tu ne sais pas ce qu'il faisait.

Pas vilain!

Jour 4 17 septembre

Grosse journée pour moi car j'aurai ma première de deux présentations tantôt. J'écoute Anthony Williams ce matin (voir la dernière présentation d'hier, que je n'ai pas pu voir en direct pour des raisons familiales), mais ce sera un examen segmenté car il y a beaucoup à faire.

Je discute un peu avec le bénévole qui m'accompagne cette semaine, Farbod Ahmadian, pour les ajustements techniques de dernière minute. Il fait de l'excellent travail, et je l'apprécie beaucoup.

Vidéo : https://www.youtube.com/watch?v=udKNou797Zc&feature=youtu.be

C++ Committee's Library Evolution Working Group

Les participants de ce matin sont Ben Craig, Billy Baker, Tom Honermann et Corentin Jabot

Ben Craig présente le quatuor avec humour. Ce sont quatre très chics types.

Q : quel est, dans la bibliothèque, votre élément préféré de C++ 20

Corentin Jabot : les ranges, qui nous rendent nettement plus productifs

Tom Honermann : les concepts; ils rendent la programmation vraiment plus agréable

Billy Baker : il y en a plusieurs, mais j'ai un faible pour <numbers>. Je suis ravi de voir disparaître les dix-sept versions de π dans ma compagnie

Ben Craig : j'ai un faible pour format()

Q : comment progressent les travaux de Freestanding

Ben Craig : on a espoir pour C++ 23, et le plus gros morceau n'est pas dans la bibliothèque; c'est que nous n'imposerions plus operator new par défaut

Q : devrions-nous avoir Networking en C++ même sans chiffrement de données?

Tom Honermann : on en a parlé à Belfast. Je suis ambivalent. La sécurité est extrêmement importante, mais il existe des cas d'utilisation pour quelque chose de plus simple

Corentin Jabot : je pense que le Networking sans chiffrement est dangereux. Nous enverrions un signal malsain à la communauté. Nous avec les exécuteurs asynchrones en marche; nous devrions n'avoir qu'un seul modèle de communication asynchrone. Vous pouvez utiliser Boost.ASIO en attendant

Ben Craig : les vendeurs sont préoccupés par la question du chiffrement; Apple et Microsoft ont tous deux des règles qui ne permettent pas de transporter des données non-chiffrées sur un réseau... C'est tentant de soutenir l'argument selon lequel on devrait construire le chiffrement sur un substrat plus simple...

Q : pourrait-on espérer une bibliothèque de std::encryption?

Corentin Jabot : c'est un sujet de recherche et de développement. Supprimer des éléments dépréciés est un défi pour le standard. Aussi, les experts en cryptographie sont très spécialisés, et nous sommes des super généralistes

Billy Baker : nous en parlons depuis des années. Ce serait... difficile.

Tom Honermann : c'est raisonnable à mes yeux de supporter quelques algorithmes dans le standard; il y a des risques de bogues, mais c'est la même chose pour les tiers partis

Ben Craig : un des arguments de vente d'OpenSSL est une certification de l'industrie, ce qui est difficile à obtenir... et coûteux. Nous compétitionnerions contre ce type de produit

Tom Honermann : la compétition est quelque chose de sain. L'existence d'une API standard ne fera pas disparaître OpenSSL

Q : qu'en est-il des bris d'ABI avec l'avènement d'Unicode?

Tom Honermann : la décision à Prague n'est pas vraiment une décision. On risque de briser regex à moyen terme, à tout le moins, même si ce n'est que pour ajouter un format d'expression régulière. Ajouter des fonctions globales n'est pas un problème; imposer un encodage de caractères à std::string ne passera pas

Corentin Jabot : pour std::string, on a un type qui n'est pas approprié pour du texte. On examine un nouveau type, peut-être std::text

Ben Craig : ce type d'enjeu apparaît ailleurs aussi, par exemple dans <iostream> pour des enjeux de formatage

Q : quelle était la plus difficile décision à prendre à l'échéance de C++ 20?

Ben Craig : nous ne sommes pas la bonne audience pour ceci, car LEWG relaie des propositions à LWG et ce sont eux qui tranchent

Billy Baker : ce qui est plus difficile est de décider ce que nous ne relaierons pas

Corentin Jabot : nous avons relayé plusieurs choses que nous aurions aimé avoir pour C++ 20, et qui ne seront là que dans C++ 23 car le pipeline de LWG est plein

Tom Honermann : pour moi, les deux plus difficiles décisions étaient modules et coroutines, car nous n'avions pas implanté le tout dans la bibliothèque, donc moins d'expérience. Pour les coroutines, nous avons eu une bonne rétroaction du terrain, mais j'ai hâte de voir ce que nous pourrons faire d'ici C++ 23 cen ce sens

Q : où en est std::expected<T,E>?

Billy Baker : on en a parlé cette semaine. Bryce Adelstein Lelbach a des positions marquées à ce sujet, et il sera là cet après-midi. C'est en cours de traitement...

Ben Craig : je pense que les probabilités d'avoir std::expected<T,E> pour 2023 sont faibles, mais peut-être 75% pour 2026. Ça dépend de la progression des autres propositions de gestion d'erreurs. C'est un sujet important

Q : Corentin Jabot, peux-tu nous raconter le jour où la bibliothèque standard est morte? 🙂

Corentin Jabot : ça fait référence à un de mes blogues. Elle n'est pas morte... encore, mais les enjeux d'ABI contraignent son évolution. Elle est moins compétitive pour cette raison. Je ne veux pas qu'elle soit là, mais moins intéressante parce que l'ABI la tire vers le bas

Ben Craig : j'ai lu sur Reddit que des gens sont d'accord avec Corentin Jabot. Je pense que le comité comprend ces enjeux. Je pense que la transition de auto_ptr<T> vers unique_ptr<T> peut nous guider. Se lancer dans une version 2 de unordered_map est... périlleux

Tom Honermann : la solution est de demander à Corentin Jabot d'écrire une proposition 🙂

Corentin Jabot : on peut s'aider en utilisant les concepts dans nos interfaces, pour faciliter une transition

Q : je viens d'écrire une petite structure de données pour système embarqué. Peut-on envisager des structures de données appropriées pour ces systèmes dans la bibliothèque standard?

Billy Baker : le terme « système embarqué » est un vaste chapiteau. Faudrait commencer par une proposition écrite 🙂

Ben Craig : les structures de données sont compliquées ici dû à l'allocation dynamique de mémoire et au traitement des erreurs; standardiser des conteneurs sans ces mécanismes est difficile. Dans Freestanding, on n'a que std::array. Un fixed_capacity_vector est proposé, mais a encore recours aux exceptions. J'espère que les exceptions statiques de Herb Sutter nous aideront à faire le pont ici. J'ai plus espoir pour un intrusive_list que pour un dynamic_array

Tom Honermann : il y a quand même les vecteurs constexpr...

Ben Craig : j'ai espoir. Peut-être sous un chapeau global de « Tout est Ok si c'est à la compilation »

Q : peut-on espérer un outil standard pour interagir avec des bilbiothèques tierces (un Package Manager)?

Corentin Jabot : la communauté C++ avec ses macros se complique un peu la vie dans la mise en place d'un écosystème

Ben Craig : le comité ne produit pas des outils, il produit des spécifications. Idéalement, on standardiserait les pratiques existantes. Aussi, si nous adoptons un Package Manager spécifique, il y aura un délai pour que ce soit accepté par la communauté

Tom Honermann : je suis en faveur de la compétition. J'aime bien les outils sur Linux, j'aime bien vcpckg. Faudrait les appuyer

Q : a-t-on brisé l'ABI de manière importante dernièrement, outre std::list et std::string?

Ben Craig : l'allocation alignée avec les propriétés souhaitées briserait quelque chose chez MSVC

Corentin Jabot : je pense que les bris avec std::string ont fait peur aux gens...

Ben Craig : changer le type de retour de emplace_back() était un bris d'ABI technique, mais ça n'a pas trop paru

Tom Honermann : avec std::filesystem, on a une fonction qui retourne un std::u8string plutôt qu'un std::string et ça n'a pas trop paru

Q : pourquoi y a-t-il tant de chemises hawaïennes au comité?

Billy Baker : on va régulièrement à Hawaï... pour s'enfermer dans une pièce sans fenêtres

Tom Honermann : notre symbole devrait être l'ananas

Ben Craig relate le Inappropriate Tee-Shirt Day de chaque rencontre du standard

Q : si POSIX parvient à imposer un format à la ligne de commande, pourquoi pas WG21?

Ben Craig : ça ne nous revient pas. Avec la proposition sur std::compile de René Rivera, on a presque imposé un format de manière détournée, mais ça n'a pas passé (du moins, pas encore)

Corentin Jabot : en pratique, C++ ne requiert pas un compilateur (il évoque Cling)

Tom Honermann : dans le futur, ce qui peut être important est les modules, pour lesquels un manifeste décrivant les modalités de génération pourrait être utile. Exprimer les requis de compilation serait pertinent ici

Q : devrait-on produire une nouvelle versions de la bibliothèque standard pour laquelle il n'y aurait aucune stabilité d'ABI?

Corentin Jabot : j'ai joué avec l'une des bibliothèques standards dernièrement, et juste passer de C++ 11 à C++ 20 m'a permis de retirer les deux tiers du code. On peut faire évoluer les choses autrement.

Ben Craig : même si on ne se préoccupait pas d'ABI, il y a des choses qu'on ne changerait pas, pour ne pas briser les interfaces. Je note que libc++ a une option de compilation qui brise tout au besoin, et que gcc a quelque chose de semblable. Les bibliothèques sont toutes à code ouvert maintenant, alors vous pouvez essayer!

Q : quel est le chemin pour choisir entre stabilité et progrès?

Billy Baker : on discute beaucoup de l'annexe D (deprecated...). Entre autres, strstream est déprécié depuis longtemps mais est encore là. On ne devrait pas avoir peur de faire disparaître auto_ptr. Pour les trucs dépassés sans être brisés (bind() par exemple), je ne sais pas

Tom Honermann : on veut éviter des fonctions suffixées par ex, exex, ex2, etc. mais si on veut tout maintenir, on va y arriver là

Ben Craig : on peut s'améliorer, entre autres en pensant à un mécanisme de versionnage pour tout ce qui exige une délégation dynamique (méthode virtuelle, pointeur de fonction) pour nous permettre de raffiner le modèle ultérieurement

Corentin Jabot : c'est une discusion qui dure depuis plusieurs années, et il est difficile de trancher

On ferme juste à temps pour courir vers nos rencontres subséquentes. Je vais vers generate_n() pour voir et entendre l'illustre Walter E. Brown

Walter E. Brown – What's in a Name? What's a Name In?

Walter E. Brown remercie les gens de venir à sa rencontre. Il commence par remercier son épouse qui fabrique ses cravates depuis des années; il en montre une qui n'est faite que de zéros et de uns, et dit que son épouse lui a fait un masque de la même fabrique... un bit-mask 🙂

Walter E. Brown parle du pouvoir des noms, dans les mains des sorciers entre autres (je l'aime!)

Choisir un nom a été discuté par le passé, par Kate Gregory entre autres. Il souhaite plutôt parler du traitement des noms dans noms programmes. Walter E. Brown dit que le sujet des noms en C++ est si complexe qu'une heure ne suffiraiat pas; on découvre de subtilités sans cesse. Il mentionne au passage les changements récents résultant de l'arrivée des modules, puis de N1787 qui changerait encore beaucoup de choses dans les règles existantes

Walter E. Brown dit donc souhaiter se pencher sur les principes sous-jacents, avec exemples tirés pour l'essentiel du standard lui-même

(j'ai eu une coupure de signal de deux minutes 😒)

Walter E. Brown trace un bref historique de l'utilisation de noms dans les programmes. Il nous joue une brève vidéo de Maurice Wilkes qui montre ce qu'était programmer en 1951. Du bonbon

Comment programme-t-on avec des noms? Parfois, on associe des noms à des valeurs, parfois à des endroits (ce qui nous évite l'irritant de manipuler les endroits numériquement). En général, la plupart des noms disparaissent dans la transformation en code machine (outre les symboles publics).

Walter E. Brown : pour utiliser un nom, il faut habituellement l'introduire et en explique le sens. C'est une déclaration (certaines déclarations sont aussi des définitions). En C++, il est souvent possible de déclarer sans définir tout de suite; il faut parfois joindre déclaration et définition; il est parfois possible de se limiter à une déclaration. Certains noms sont même prédéfinis. Walter E. Brown donne quelques exemples

Walter E. Brown indique la définition officielle de [lex.name] et [basic.def], et l'explique. Certains identifiants sont spéciaux et réservés (mots clés, représentations alternatives comme and ou not, mot débutant par __ ou par _[A-Z]). D'autres sont parfois réservés, les mots-clés contextuels (ce qui commence par _ dans l'espace nommé global par exemple)

Walter E. Brown dit réfléchir les déclarations comme des paires nom,valeur où la valeur est la sémantique associée.

Certaines déclarations ont peu ou pas d'effet, par exemple les redéclarations, la spécialisation explicite d'un template (qui n'introduit pas un nouveau nom), la déclaration vide, static_assert...

Walter E. Brown dit que chaque nom est déclaré dans son contexte, son Name Space (deux mots). En C++, on nomme ceux-ci une région déclarative (on parle souvent de portée, informellement). Tout nom est injecté dans un contexte, pas nécessairement le même que celui de sa déclaration (il parle de friend en particulier); le nom fait alors partie du contexte dans lequel il a été injecté. Utiliser un nom se fait aussi dans un contexte (exception faite des macros, qui ne sont pas réellement du C++)

Walter E. Brown mentionne les régions déclaratives : bloc, fonction, paramètre de nom, namespace, etc. (il y en a une dizaine). Un nom nouvellement introduit est injecté dans son contexte, mais pas nature friend est un peu différent et est injecté dans le plus proche namespace englobant; il y a des subtilités en ce sens, qui permettent les Hidden Friends

Walter E. Brown mentionne aussi les using directives qui fait apparaître un nom comme s'il avait été injecté. Un namespace anonyme et un namespace qui serait inline ont aussi des effets atypiques.

Walter E. Brown y va d'un exemple :

namespace N {
   int k; 
   int g(int a) {return a; } 
   int p(); 
   void q(); 
}
namespace {int b = 1; }
namespace N { // réouvert
   int g(char a) {
      return b + a; // ::b donc Ok
   }
   int k; // erreur (bris d'ODR)
   int p(); // Ok (redéclaration)
   int p() { return g(k); } // Ok (redéclaration et définition)
   int q(); // erreur : ne surcharge pas N::q() car seul le type de retour change
}

Walter E. Brown : que se passe-t-il quand un réutilise un nom préalablement déclaré? Le compilateur s'en sert comme clé pour trouver ce qui lui est associé. C'est le Name Lookup, une famille d'algorithmes qui interagissent avec un ensemble de cas particuliers, et l'un des aspects les plus complexes de C++. Walter E. Brown mentionne un cas où les noms de fonctions sont ignorés... Il ne sait pas pourquoi c'est là

Walter E. Brown demande pourquoi ces algorithmes sont si compliqués. Il fait une mise en situation (nom dans une boucle, membre d'une classe, interne à une autre classe, dérivant de trois classes, chacune avec ses parents, dans divers espaces nommés, dont l'un rendu visible par un using directive...)

Walter E. Brown donne une liste non-exhaustive d'une vingtaine d'aspects du langage qui influencent la complexité du Name Lookup

Walter E. Brown mentionne ensuite six algorithmes de Name Lookup, dont ADL, et indique qu'il arrive qu'un cas corresponde à plus d'un algorithme. Dans [basic.lookup], heureusement, on dit que soit ces noms décrivent tous la même entité, soit ils forment un Overload Set, dans lesquels il faut faire un Overload Resolution.

Chaque nouveau nom introduit est comparé par le compilateur avec les noms préalablement introduits. Les déclarations suffisent ici (pas besoin d'utiliser les noms).

Walter E. Brown propose un autre exemple :

typedef int f;
namespace N {
   struct A {
      friend void f(A&);
      operator int();
      void g(A a) {
         int k = f(a); // de quel f s'agit-il? 
      } 
  }; 
}

Walter E. Brown : la réponse est le f du typedef. La raison est que la fonction friend est injectée dans N, et qu'il n'y a pas de déclaration de cette fonction dans N. La recherche trouve donc l'alias de f à int, et appelle operator int()... C'est un cast! ADL trouverait la fonction, mais ce cas ne l'invoquera pas

Autre exemple :

namespace A::N {
   void g(); 
}
void A::N::g() {
   // ...
   k = 5; // où le compilateur chercherait-il le nom k?
   // ... 
}

Walter E. Brown explique que la recherche faite par le compilateur pour k serait, dans l'ordre : dans A::N::g() avant l'utilisation de k (pas après); puis dans A::N là où g() est déclarée; puis dans A, puis dans le namespace global avant la définition de A::N:g() (pas après)

Autre exemple :

namespace M {
   class B {}; 
}
namespace N {
   class Y : public M::B {
      class X {
         int a = k; // où le compilateur cherchera-t-il k?
      }; 
   }; 
}

Walter E. Brown explique que la recherche se fera, dans l'ordre : dans N::Y::X avant l'utilisation de k, puis dans N::Y avant la définition de X, puis dans M::B, puis dans N avant la définition de Y, puis dans l'espace global avant la définition de N.

Autre exemple :

namespace N {
   int a = 4;
   extern int b; // déclaration 
}
int a = 2;
int N::b = a; // quel a?

Walter E. Brown dit que a sera trouvé dans N::a car utiliser N::b nous place dans le contexte de ce namespace

Walter E. Brown mentionne un cas étrange :

int S; // définition
struct S { /* ... */ };

Il se trouve que S est multiplement déclaré, mais qu'en l'absence d'une fonction ce n'est pas une surcharge. La variable cache le type pendant un Unqualified Name Lookup. Ça vient de C... Faites pas ça!

class S { /* ... */ };
S S; // Ok mais pas fin
S T; // oups, S est la variable maintenant, ne compile pas
class S U; // Ok, on a clarifié l'intention

Walter E. Brown cite Gabriel Dos Reis qui rappelle que ça a été fait pour fins de compatibilité avec C...

Walter E. Brown mentionne d'autres formes de Lookup. Il commence avec ADL, dont il cite [basic.lookup.argdep] :

namespace N {
   struct S {};
   void g(S); 
}
// ...
void h() {
   N::S s;
   g(s); // unqualified name lookup ne trouve rien, mais ADL fouille dans N et trouve N::g(N::S)
   (g)(s); // (g) est une expression, et ne fouille pas ailleurs. unqualified name lookup ne trouve rien, mais il n'y a pas d'ADL. Ça ne compile pas
}

Walter E. Brown poursuit avec les autres sortes de Lookup. Il mentionne Qualified Name Lookup et Member Access Lookup. Les deux fonctionnent de manière semblable, mais Qualified Name Lookup utilise :: alors que Member Access Lookup utilise . et ->. Ce qu'ils ont en commun est d'examiner d'abord l'opérande de gauche, qui donne le contexte pour comprendre l'opérande de droite. Ces opérations ne provoquent pas d'ADL par elles-mêmes

Walter E. Brown termine avec un dernier exemple, pour aider à comprendre ce que doivent traiter les membres du comité :

struct A {};
namespace N {
   struct A { ~A(); }; 
}
struct C : N::A {};
struct B : A, C { // A est ::A ici
   ~B();
   using A = C; 
}; // oui, tout ça est légal
B *pb; // = ... ou peu importe
// ...
int main() {
   bp-> A::~A(); // oops! Which A?
}

Walter E. Brown : sans lire le tout en détail, ceci donne un aperçu du niveau de difficulté analytique impliqué (il montre des extraits des discussions; on ne sait pas si c'est correct, juste l'effort analytique requis)

Walter E. Brown termine avec une citation d'Alice 🙂

Ok, celle-là était un chef-d'oeuvre. Ouf!

J'avais le nez congestionné hier soir (évidemment, la veille de ma première conférence) et mon amoureuse Za m'a préparé une soupe aux tomates (réconfortant) à partir de tomates fraîches (délicieux!), ce qui m'a permis de consommer un petit bol de bonheur entre les présentations de Walter E. Brown et de Lisa Lippincott. Je dois avouer que suivre ces deux-là est un défi insurmontable, alors mieux vaut être serein et faire de mon mieux...

Jon Kalb nous informe qu'il y aura des ajouts à l'horaire, pour saisir la rétroaction des participantes et des participants.

Vidéo : https://www.youtube.com/watch?v=Zjy8RCb8p7M&feature=youtu.be

Lisa Lippincott – Neighborhoods Banding Together: Reasoning Globally about Programs

Lisa Lippincott commence en indiquant que le C++ utilisé aujourd'hui est du pseudo-C++.

Lisa Lippincott : raisonner localement, c'est raisonner sur le voisinage du code que l'on regarde. On peut typiquement raisonner à partir des déclarations, mais il faut aussi tenir compte du corps des fonctions inline.

Lisa Lippincott présente le raisonnement comme un jeu entre les cornus et les chauves. Les cornus représentent l'extérieur du voisinage; les chauves visent à réaliser le traitement dans les fonctions et à pousser le fruit des calculs vers l'écriture. Lisa Lippincott sépare une fonction en prologue, implémentation et épilogue; les cornus contrôlent le prologue, et l'objectif est de s'assurer que les chauves gagnent localement

Lisa Lippincott : le but est de placer toutes les fonctions ensembles. Chaque chauve traite ses collègues comme des cornus, et les chauves (raisonnant localement) souhaitent que la partie dans son ensemble soit gagnée par les chauves.

Lisa Lippincott : le problème que nous explorons aujourd'hui est l'intégration des fonctions, qu'aucun chauve ne voit.

Lisa Lippincott explique qu'il arrive des cas où l'appelant et l'appelé ne sont pas pleinement d'accord sur la sémantique d'un appel, et que cela peut faire s'écrouler l'ensemble. C++ a une règle pour éviter cela, et c'est ODR, qui nous impose de ne pas avoir de définitions qui ne soient pas faites de la même séquence de jetons, et qui exige que si plusieurs unités de traduction réfèrent à une fonction, elles réfèrent toutes à la même (il y a des exceptions, par exemple quand il existe plusieurs objets constants avec une même valeur, quand seule la valeur importe)

Lisa Lippincott : je vais étendre ODR pour dire que l'implémentation est des fichiers .cpp et l'interface des fichiers .h, avec l'exception des fonctions inline. Une définition sera un mapping entre un linkage name (jetons, valeurs, etc.) et le linkage name d'autres entités

Lisa Lippincott : chaque unité de traduction (où une unité de traduction est un ensemble de voisinages) peut avoir un lien des définitions dont elle dépend. Si nous avons un portrait global de ces dépendances, ODR peut être totalement diagnostiqué. C++ ne l'exige pas car nous ne contrôlons pas l'édition des liens. Suffit de faire sort, puis unique, puis find_adjacent pour trouver les violations d'ODR au fond

Lisa Lippincott : le raisonnement commence par une phase locale, qui valide les petits voisinages, et décrit les interactions de manière concise avec de petites tables. Ensuite, une phase global intègre ces tables pour valider les interactions. Local : algos complexes, petites données; global : algos simples, données massives. C'est une approche échelonnable.

Lisa Lippincott parle ensuite de l'interface des fonctions, qui permet de savoir si la fonction convient à nos besoins. Elle distingue les appels directs, où nous savons précisément ce que nous voulons, des appels indirects. Elle introduit ce qu'elle nomme un Interface adapter, qu'on ajoute devant une fonction existante, à la manière d'une instanciation de template. L'avantage de cette approche à la template est qu'elle crée un nouveau voisinage de raisonnement

Lisa Lippincott présente trois modalités d'Interface adapters : indirection par pointeur de fonction, indirection par méthode virtuelle, indirection par pointeur de méthode. Elle fait remarquer qu'il arrive qu'une récursivité à plusieurs niveaux s'introduise si un cycle se crée, et ce cycle est invisible à l'interne pour les chauves. C'est un problème global, pas un problème local. Cette récursivité peut être sans limite (vilain) ou être finie (raisonnable dans bien des programmes). Elle décrit des caractéristiques d'une récursivité limitée acceptable (elle converge vers la fin avec chaque cycle, n'en diverge pas, et se termine éventuellement). Le fait que ces règles mentionnent des cycles est une preuve que le problème est non-local. Il se peut toutefois qu'un chauve nous rapproche à chaque itération de la fin (cela peut se constater localement)

Lisa Lippincott décrit une stratégie pour détecter ces cycles récursifs par des actions locales et par des actions globales. Elle montre comment chaque voisinage peut créer sa propre table locale d'informations sur les actions prises (p. ex. : rapprochement de la fin de la récursivité). Par la suite, elle génère une table de ces sous-tables, puis génère une forêt. Le graphe qu'elle génère contient des flèches qui reviennent vers l'arrière (on cherche des cycles!), mais il y a une logique là-dedans puisqu'on examine une interaction entre appels de fonctions. C'est un algorithme de détection de cycles mais ciblé pour le problème de la réduction de la récursivité

Lisa Lippincott dit que l'algorithme entier est O(n log n)

Lisa Lippincott aborde ensuite la question de la définition d'une frontière de récursivité, particulièrement dans le cas d'une détection globale / locale comme celle-ci. Elle montre un distance() tail-recursif, qu'elle exprime dans son langage qui sépare prologue, implémentation et épilogue. Elle propose une claimable function, qui affirme que l'exécution d'une fonction se terminera et retournera le contrôle à l'appelant. Son inline claimable recursively_rechable(b,e) est inline, manifestement, et fait donc partie du voisinage de l'appelant (qui l'utilise dans une clause claim)

Lisa Lippincott rappelle qu'on ne s'intéresse pas au raisonnement local aujourd'hui, mais que d'un point de vue algorithmique pour une fonction récursive on parle d'un algorithme de comparaison de branchements. Elle note que pour une fonction localement récursive et inline, la démonstration d'un appelant peut profiter de la démonstration de l'appelé par voie de programmation dynamique

Lisa Lippincott dit aimer que pour prouver le fonctionnement d'une fonction localement récursive, il faut construire un modèle de son calcul. Elle montre comment construire un modèle semblable pour traverser un arbre, ou pour modéliser une récursivité mutuelle à deux fonctions. Elle recommande de Represent Like with Like : stat rosa pristina nomine, nomina nuda tenemus (TRADUCTION FRANÇAISE)

Q : Since memory addresses are just 64 bit integers, wouldn't that mean that, technically, any pointer is reachable from any other pointer

Lisa Lippincott : il y a deux idées de Reachable en jeu ici. En général, la réponse est non. On tomberait dans le comportement indéfini dans l'évaluation du modèle, ce qui brise le raisonnement local. Les pointeurs ne sont pas équivalents à des entiers dans le langage, et ne sont pas soumis aux mêmes règles

Q : ceci ne devrait-il pas tomber dans le domaine des analyseurs statiques?

Lisa Lippincott : je pense que oui. L'oeuvre de ma vie est de nous amener là, vers des programmes plus corrects. L'interaction entre le compilateur et l'édition des liens est nécessaire

Q : I **think** that this whole thing is describing a kind of whole-program correctness analysis, and the additional notation would really be a "language addition" to help that analysis?

Lisa Lippincott : en effet. Si j'étais « roi de C++ », ces trucs seraient dans C++ 20, mais je me serais probablement trompée en le faisant toute seule. C'est une bonne chose de ne pas être seule!

Q : où aller pour en savoir plus?

Lisa Lippincott : j'ai quelques conférences disponibles sur YouTube (j'ai un faible pour The Truth of a Procedure, dit-elle). Elle dit planifier une présentation nommée The Halting Problem is not Our Problem : les programmes sont des artéfacts de l'intention humaine, et le problème de l'arrêt, si valide soit-il, ne tient pas compte de cette intention. Automatiser la revue de code est possible en pratique

Q : What other properties of local or global reasoning that you still have to explore?

Lisa Lippincott : je préparais à l'origine une présentation sur l'utilisation saine de variables globales. La présentation d'aujourd'hui devait n'en être que le prologue. Ça donne une idée... Aussi, comment divers voisinages peuvent-ils se faire des promesses mutuellement? Aussi, pourquoi les répétitives se terminent-elles?

Q : Are there any examples of languages besides C++ that have achieved this kind of static analysis?

Lisa Lippincott : plusieurs ont réussi. Ada y a investi beaucoup d'efforts; j'ai commencé avec The Science of Programming par David (Greiss?), et cela a influencé ma pensée. Je préfère travailler avec un langage existant.

C'était riche et intéressant! Direction vers count_if() pour ma propre présentation maintenant. On se croise les doigts...

Vidéo : https://www.youtube.com/watch?v=Wg1f9Sufyic&feature=youtu.be

Diapos : https://github.com/CppCon/CppCon2020/blob/main/Presentations/the_surprising_costs_of_void/the_surprising_costs_of_void__patrice_roy__cppcon_2020.pdf

Patrice Roy – The Surprising Costs of void() (and Other Not-Quite-Innocuous Evils)

J'ai fait de mon mieux. Il semble qu'il manque les 40 premières secondes de la présentation sur Remo, mais que le lien YouTube sera complet. J'ai fini à 4 minutes de la fin, et j'ai eu six ou sept questions de même que plusieurs commentaires tout à fait charmants. Je pense qu'un peut dire que c'était un succès. Ouf; j'ai travaillé fort!

Espérons que celle de demain fonctionnera bien elle aussi.

Petite jasette agréable avec Victor Bogado et Guy Davidson en attentdant que David Sankel ne débute. Je reçois des messages très gentils par divers canaux, incluant un de mon ami Walter E. Brown qui est très touchant.

Vidéo : https://www.youtube.com/watch?v=giWCdQ7fnQU&feature=youtu.be

David Sankel – Monoids, Monads, and Applicative Functors: Repeated Software Patterns

David Sankel explique que les modèles qu'ils nous présentera sont fortement composables. Ils ne sont pas là pour les usagers; ils sont là pour les programmeuses et les programmeurs (n'exposez pas un truc nommé Monad::Bind par exemple).

David Sankel rappelle qu'écrire du code générique est agréable, mais qu'écrire du code lisible est encore plus important.

David Sankel fait un détour par Haskell, qu'il dit modelé sur les mathématiques et dont il vante le choix de la pureté (pour un ensemble d'intrants donné, on aura toujours les mêmes extrants, et sans effets de bord). Initialement, Haskell peinait à réaliser des tâches pratiques comme les entrées / sorties, mais avec les monades en 1992 il devenait possible de modéliser les états et les entrées / sorties. Cela a transformé Haskell d'un langage un peu jouet à un langage utile.

David Sankel trace un bref historique de la théorie des catégories, et en vante la généralité et l'applicabilité à d'autres domaines, par exemple la musique.

David Sankel dit que les Patterns dont il parlera aujourd'hui viennent de la nature, des lois de la physique, il ne parle pas de schémas de conception.

David Sankel débute par le monoïde, qu'il définit comme un type associé à une opération binaire (deux opérandes) qui doit être associative et avec un élément neutre (note : c'est une présentation pré-enregistrée, mais de très bonne qualité et très divertissante; il pose des questions et des enfants répondent 🙂). Par exemple, les entiers avec + et 0, ou les entiers avec * et 1, ou encore max et 0 sur les entiers naturels.

David Sankel demande quel est l'élément neutre pour float et std::max(). Il demande aussi quelle serait l'opération pour un monoïde sur std::vector<T> (ce serait la concaténation et un vecteur vide)

David Sankel quel est l'intérêt d'avoir des monoïdes? We can Squash them. Ça se réduit et ça se simplifie... Ça se compose

David Sankel demande si optional<T> est un monoïde. La réponse est oui : l'opération est append(a,b) qui garde a si b est vide, b si a est vide, et qui squash(a,b) sinon

David Sankel présente un monoïde sur deux std::function<monoid(A)> qui fait que ce que fais avec f_g_x(F,G). Il discute ensuite d'un monoide capable de chercher des mots dans un document. Les monoïdes sont composables et échelonnables.

David Sankel poursuit avec les foncteurs au sens de la théorie des catégorie : un template<class>, avec une fonction map qui combine deux foncteurs (ça ressemble à mes métafonctions). Mon f_g_x est un de ses exemples. Les foncteurs sont un peu comme des conteneurs

(j'ai manqué une petite minute)

David Sankel demande si optional<T> est un foncteur, et la réponse est oui (il montre un exemple). Il demande ensuite si pair<T,U> est un foncteur, et la réponse est oui... mais seulement si T est fixé et U peut changer. Il demande si function<R(Args...)> est un foncteur, et la réponse est oui... si tous les types sont fixés. Il donne un exemple de Map dans chaque cas

David Sankel présente un vector<optional<T>> et montre comment composer des foncteurs et aller chercher un vector<T>

David Sankel aborde ensuite les foncteurs applicatifs, qui ont les opérations pure() et apply(). C'est plus abstraits et il y a des lois, mais il passe rapidement. En gros, pure() place une valeur dans un conteneur, et apply() opère sur ce conteneur Pour optional, pure(T) retourne un optional<T>{ t } a alors que apply(optional<function<T(T)>, optional<T>) retourne un optional<T> contenant peut-être le résultat de l'application de la fonction

David Sankel demande si vector<T> est un foncteur applicatif. Il peut définir pure(), et examine comment définir apply (qui applique des fonctions aux valeurs). On arrive à un non-déterminisme mais j'ai manqué un truc en m'occupant d'un chien... Zut!

David Sankel aborde les Parser Applicative Functors, pour définir une interface pour une bibliothèque de processeurs de langages. Il construit un exemple simplifié de Parser<T>. Une des fonctions qui l'accompagne est Parser<T> either(Parser<T>,Parser<T>)... Je ne note pas tout, mais c'est intéressant. Ce qui manque est probablement : pourquoi procéder ainsi. Une fois la structure de base en place, il montre comment on peut l'appliquer pour traiter du texte. C'est joli.

David Sankel dit que les monoïdes sont fortement parallélisables. Les foncteurs opèrent sur ces « trucs à l'intérieur »... Maintenant, une monade est un foncteur applicatif avec une opération join. Il montre comment faire une monade qui prend un optional<optional<T>> et retourne un optional<T>

David Sankel s'intéresse à l'intérêt (!) des monades. L'intérêt est bind, qui permet un peu de transformer du code fonctionnel pur en code impératif. Elles permettent d'exprimer des idées plus riches en C++ comme des continuations ou des DSL par exemple. Quand on fait de la métaprogrammation à l'aide de templates, on donne dans les monades

David Sankel prend ensuite les questions. C'est du bon boulot! Il se présente en personne et est de très bonne humeur

Q : qu'as-tu donné aux enfants pour qu'ils participent?

David Sankel : ce sont des amours

Q : comment as-tu préparé le tout?

David Sankel : un téléphone sur un trépied pour moi, même chose dans une autre pièce avec les enfants, beaucoup de montage

Q : as-tu des bloopers?

David Sankel : ce serait chouette!

Q : peut-on formuler ces idées sous forme de concepts?

David Sankel : les monoides, absolument. Le reste, je ne suis pas sûr

Q : quand on débogue ces trucs en C++, à quel point est-ce douloureux?

David Sankel : c'est semblable à d'autres types de métaprogrammation

Q : que recommandes-tu aux gens qui essaient de comprendre Haskell et n'y arrivent pas?

David Sankel : si c'est ardu, c'est que ça vaut la peine. L'implémenter soi-même est instructif

Q : penses-tu que l'absence de syntaxe en C++ pour les monades rend le tout inutilement difficile?

David Sankel : la do-notation de Haskell serait peut-être chouette, mais on peut faire beaucoup de chemin juste avec des fonctions

Q : la terminologie me semble obscure mais je pense comprendre les idées. Comment devenir meilleur(e)?

David Sankel : le mettre en application, beaucoup et souvent, pour déveopper une intuition de ce que c'est. Quand on comprend, one est heureux et on veut le dire à tout le monde... et personne ne comprend

Q : qu'ajouterais-tu à C++ pour le rapprocher de tes idées?

David Sankel : le Pattern Matching bien sûr :) On travaille fort pour C++ 23

Q : as-tu un exemple de quelque chose qui n'est pas un foncteur?

David Sankel : quelque chose comme un int, qui n'a pas de Map. Les foncteurs sont très, très communs

Q : peut-on implémenter tout cela par template metaprogramming?

David Sankel : oui, surtout si on souhaite que ça ressemble plus à du code impératif (la métaprogrammation avec des templates est très fonctionnelle)

Q : comment définir une meilleure interface pour fins d'utilisabilité?

David Sankel : c'est une forme d'art. Exposer les opérations les plus communes, peut-être à titre de méthodes, est un point de départ. Consulter des utilisateurs-non-auteurs pour leur opinion

Q : as-tu un exemple canonique de comonade?

David Sankel : rien ne me vient, mais je vais y réfléchir. C'est un peu plus obscur que les monades

Q : en quoi une monade est-elle considérée pure?

David Sankel : c'est parce qu'elles prennent un calcul en bloc, et le font apparaître comme étant réalisé dans un autre univers. Une boîte noire... Ça permet de composer des impuretés d'une manière pure

Q : pourrait-on rendre ton Parser<T> compétitif avec des processeurs de langage traditionnels?

David Sankel : je ne sais pas, mais on peut en faire de très bons

Q : est-ce trop étrange pour C++?

David Sankel : ce qui est attirant est que la beauté de ces structures mathématiques nous font tomber en amour. Je suis un ingénieur logiciel; j'utilise ces outils pour qu'ils soient utilisés et aient un impact positif sur le monde. J'aime bien des trucs come Agda, qui sont archi purs, mais ce n'est pas pratique

Q : as-tu un exemple de bind?

David Sankel : le .then() des continuations

Q : Scala a des monades. C++ s'en va-t-il dans cette direction?

David Sankel : C++ est un langage d'ingénierie logicielle. C++ progresse par priorités. Ce ne serait pas sur ma liste personnelle de priorités même si ça me rendrait heureux

Q : qu'en est-il de Lazy Evaluation?

David Sankel : il y a des propositions. Ce qui bloque est le manque de cas d'utilisation qui amèneraient ceci sur le dessus de la pile de priorités. Haskell s'en sort bien car le langage est pur, mais C++ n'est pas pur et c'est un enjeu différent

Excellent travail. J'aimerais aller à la rencontre du LEWG mais je dois aller m'occuper des enfants un peu.

Jour 5 18 septembre

J'ai commencé ma journée en regardant (en différé) la très bonne et très rigoureuse présentation Back to Basics: The Abstract Machine de mon ami Bob Steagall. Cette présentation s'est tenue lundi pendant que j'étais ailleurs (il y a souvent plusieurs présentations qui m'intéressent et se donnent concurremment ici; il y a sept présentations à la fois, alors les probabilités étant ce qu'elles sont...). Il m'a écrit pour me dire qu'il s'est inspiré de What Machine am I coding to, que j'ai donné dans le passé, mais il a fait un bien meilleur travail que moi et je lui ai écrit pour le lui dire. Du beau travail. Voir https://www.youtube.com/watch?v=ZAji7PkXaKY pour la vidéo.

Ma deuxième et dernière présentation du colloque se tiendra cet après-midi, de même que mon AMA (une première pour moi), alors je fais les dernières retouches en préparant ce journal de « voyage ». Une autre belle journée de contenu s'annonce pour moi. Je lance Constructing Generic Algorithms: Principles and Practice par mon ami Ben Deane en arrière-plan (il est toujours excellent). J'ai vu cette semaine plusieurs présentations que je recommanderai à mes étudiantes et à mes étudiants, et les deux de ce matin sont sur cette liste (pour des raisons différentes).

Je suis dans la salle count_if() quand Peter Muldoon débute sa présentation.

Vidéo : https://www.youtube.com/watch?v=K5c7uvWe_hw&feature=youtu.be

Peter Muldoon – Retiring the Singleton Pattern: Concrete Suggestions for What to use Instead

Peter Muldoon se présente. Il travaille chez Bloomberg. Il dit avoir eu l'idée de la présentation en voyant un courriel interne mentionnant l'ajout d'un singleton dans un projet; il dit avoir conversé avec la personne ayant écrit le courriel, qui était d'avis qu'un singleton était une bonne idée (ce avec quoi il est en désaccord). Il dit en avoir vu d'autres apparaître par la suite, même dans du nouveau code, souvent dans l'optique de réduire le nombre de paramètres dans des appels de fonctions

Peter Muldoon dit avoir cherché pour le mot singleton; la moitié de ce qu'il a trouvé demandait comment écrire un singleton, et l'autre moitié semblait critiquer ce schéma de conception. Il a remarqué que très peu de gens proposaient des alternatives... D'où cette présentation

Peter Muldoon dit viser des alternatives pratiques et utiles. Refactoriser une base de code entière est... moins pratique qu'il ne le souhaiterait.

Peter Muldoon propose une implémentation « classique »... elle fuit... et son opérateur d'affectation a une signature incorrecte (c'est du code C++ 03, manifestement). Il utilise NULL... Oh boy.

Peter Muldoon liste des inconvénients avec les singletons : dépendance cachée, pas d'injection de dépendances, perte de contrôle sur l'initialisation (son code a une fonction Init... fouille-moi), dépendances à la construction entre les globales, état associé à la durée de vie du programme. Il liste ensuite les avantages : un seul objet à créer, moins de paramètres à passer aux fonctions...

Peter Muldoon dit qu'un singleton ne devrait pas être l'accès global à une ressource, mais bien de contrôler l'instanciation

Peter Muldoon tient un quiz : « est-ce un singleton ou pas? ». Ses questions confondent état global partagé et singleton... mais heureusement, il affirme que ses propositions (p. ex. : std::cout) ne sont pas des singletons. J'ai eu peur un moment...

Peter Muldoon montre un cas concret où des singletons apparaissent dans son expérience :

Response sendData(const Data &data) {

  Request req;

  return CommSing::Instance()->send(data); 

}

Il cherche à cibler les requis minimaux pour mettre un singleton à la retraite :

La nouvelle fonction doit au minimum être source-compatible

Elle doit permettre l'injection de dépendances pour fins de tests

Il propose :

Response sendData(const Data &data, CommSing *comms = CommSing::Instance()) {

  Request req;

  return comms->send(data); 

}

Ensuite, Peter Muldoon écrit un Wrapper pour remplacer le singleton, et il garde une variable static pour les gens qui tiennent absolument à préserver cette dépendance. Il réécrit sendData pour prendre un CommWrapper& à la place du CommSing* avec valeur par défaut.

Peter Muldoon montre qu'il peut réaliser l'injection de dépendances en faisant que CommWrapper::send() une méthode virtuelle (il le démontre en écrivant un CommTester dérivé de CommWrapper, et en l'utilisant dans un test). Ensuite, il écrit un Mock dérivé de CommWrapper pour faciliter les tests avec le cadriciel de test de son groupe.

Peter Muldoon utilise ensuite un std::function à la place de la méthode virtuelle, un peu comme un délégué

Peter Muldoon aborde le problème des copies; en utilisant std::function, il dit avoir introduit une copie, ce qui est un changement radical dans la gestion des états en comparaison avec le singleton original. Il fait des tests et, avec son code, la version avec méthodes virtuelles est plus rapide que celle avec std::function (ce qui est raisonnable)

Peter Muldoon reprend sa démarche et conserve la version à un seul paramètre, qu'il fait déléguer à une autre fonction prenant deux paramètres. C'est la chose à faire ici

Peter Muldoon aborde le problème de la multiplication des états avec la capacité de multiplier les CommWrapper. Il fait du Lazy Initialization avec une version maison de call_once() qui repose sur du double-checked locking. Dans une version qui se veut moderne, il utilise une variable statique locale à une fonction

Peter Muldoon poursuit et explique que le singleton est probablement utilisé à plusieurs endroits dans le code de l'entreprise, donc qu'un changement local peut ne pas suffire. Ce qu'il fait est changer le singleton pour qu'au lieu de se retourner lui-même, il retourne le DefaultCommWrapper. Cela laisse le reste du code inchangé.

Peter Muldoon aborde le problème de la dépendance à l'initialisation entre les singletons. Il mentionne une solution simple où main() initialise les singletons manuellement. En passant par des variables statiques créées au premier appel, le problème disparaît. Il montre comment faire des Mocks du résultat de cette transformation, et en quoi son système est devenu pleinement testable.

Peter Muldoon se dit d'avis que les singletons viennent par groupes, et qu'il peut y en avoir plusieurs dans une même fonction. Il propose une approche pour traiter les groupes de singletons : il place ses singletons dans un gros struct et utilise l'ordre d'initialisation des attributs Il généralise par généricité et suggère l'introduction d'un MockService; une alternative est d'avoir un struct qui réfère aux ex-singletons plutôt que de les posséder, ce qui permet le polymorphisme... donc l'injection de dépendances

Peter Muldoon parle de dépendances avec états; il loge ses fonctions refactorisées dans une classe et en utilise le constructeur pour procéder à l'initialisation de ces états

La réaction à la présentation de Peter Muldoon est positive. Je pense que ça avait sa place, mais j'ai des réserves (la prémisse me semble mal couvrir les cas d'utilisation des singletons; la refactorisation est intéressante, mais le code n'est pas à la hauteur des attentes -- il me semble qu'une réflexion serait à propos ici). Bien, donc, mais je reste un peu sur ma faim.

Je bavarde un peu avec mon chic bénévole Farbod Ahmadian en préparation de ma conférence.

Inbal Levi – Exceptions Under the Spotlight

Inbal Levi se présente brièvement et dit qu'elle compte parler d'exceptions. À titre de motivation, elle présente les résultats de sondages à propos de l'utilisation ou pas d'exceptions; l'un d'eux est plus formel et l'autre est un sondage maison qu'elle a fait.

Inbal Levi explique que plusieurs projets évitent les exceptions pour des raisons de laquo; performance raquo;. Elle explique que le Direction Group de WG21 pense que les contrats sont une voie d'avenir pour traiter les erreurs, que Herb Sutter a une proposition pour des exceptions sans surcoût, et que James Renwick a récemment publié une proposition sur les exceptions dans les systèmes embarqués. Elle dit s'attendre à des changements bientôt.

Inbal Levi présente son plan de match. Elle ne veut pas discuter de meilleures pratiques, et ne parlera pas de concurrence.

Inbal Levi présente les exceptions comme un mécanisme pour gérer des échecs. Elle dit qu'il est recommandé de dériver nos types d'exceptions de std::exception (je suis en désaccord :)) et qu'il est souhaitable de lever par valeur puis attraper par référence (Ok). Elle montre la structure d'un bloc try... catch incluant un catch(...). Elle mentionne aussi le droit de laisser fuir les exceptions, mais elle présente cela comme une fuite vers le système d'exploitation (il manque un peu de nuance ici)

Inbal Levi mentionne que les exceptions étaient présentes très tôt en C++. Elle présente des alternatives, soit les codes d'erreurs, les états d'erreurs globaux (std::errno), ... et c'est tout.

Inbal Levi dit que parmi les avantages des exceptions, on trouve l'adhésion aux pratiques recommandées et une forme de formalisme de tests. Bon... Elle rapporte aussi des critiques du modèle, même à l'origine, provenant de diverses voix estimant que les exceptions pourraient mener à des programmes de moins bonne qualité.

Inbal Levi apporte les suppositions derrière le design des exceptions, incluant la fréquence relative de leur occurrence. C'est une bonne idée de rappeler cela. Elle prétend que la bibliothèque utilise beaucoup les exceptions... Hum...

Inbal Levi passe aux coûts des exceptions. Elle commence par mentionner que setjmp/longjmp ne conviennent pas au modèle RAII de C++. Elle mentionne qu'il y a des coûts au Happy Path, et les compare aux valeurs de retour et aux globales, parlant des coûts associés à RTTI et au Stack Unwindig. Elle présente un mini-Benchmark sur le Sad Path, mais il est discutable...

Inbal Levi aborde la question de l'implémentation, mentionnant l'approche Table-Based de gcc et clang, et l'approche Frame-Based de MSVC. Selon elle, Table-Based optimise mieux le Happy Path et Frame-Based optimise mieux le Sad Path.

Inbal Levi liste ensuite les fonctions qui participent au Stack Unwinding sur gcc. Il y en a une trentaine, à l'oeil, mais elle ne dit pas en quoi c'est pertinent a`son discours.

Inbal Levi discute des étapes d'une levée d'exception : son allocation, la levée, le lookup et le cleanup. Elle mentionne qu'une exception laquo; d'urgence raquo; peut être allouée dans certaines circonstances. Le lookup appelle _Unwind_RaiseException qui cherche l'adresse où se trouve le code de gestion pour le type levé, et appelle terminate() s'il n'y en a pas. Le cleanup appelle _Unwind_Resume et appelle __cxa_begin_catch pour traiter l'exception puis __cxa_end_catch pour nettoyer et, au besoin, lever l'exception à nouveau avec _Unwind_Resume. Elle montre ce mécanisme avec un schéma

Inbal Levi poursuit avec un Design Review d'une perspective de systèmes embarqués. On veut une transmission Type-Safe, pas de surcoût, des handlers maison au besoin, la capacité de collaborer avec d'autres langages. La supposition que les exceptions sont plus rares que les appels de fonction demeure, la capacité de transmettre une capacité arbitraire d'information tient, considérer le mécanisme principalement pour fins de gestion d'erreurs, et survivre au multithtreading. Elle soulève le point qu'on pourrait aussi revisiter certaines de ces suppositions

Inbal Levi distingue erreurs de logique, erreurs récupérables et erreurs terminales, dans lesquelles elle place l'exhaustion des ressources.

À titre d'alternatives, Inbal Levi propose d'optimiser le code (réduire la taille des objets levés par exemple), remplacer certaines fonctions de la bibliothèque standard, ou utiliser d'autres mécanismes (elle mentionne les Structured Exceptions de Windows). Elle dit avoir essayé certaines de ces options, par exemple n'utiliser qu'un seul type d'exception pour réduire le poids du RTTI. Elle constate un surcoût important malgré tout, mais (elle ne le dit pas) RTTI ne se limite pas aux exceptions. Elle mentionne par contre qu'il arrive que les exceptions soient plus rapides que les alternatives

Inbal Levi a ensuite essayé de réimplémenter le code de throw pour le minimiser. Elle escamote l'allocation en passant par une globale, et appelle terminate() au lieu de propager si une propagation est indiquée. C'est intéressant, car les coûts qu'elle mesure sont presque les mêmes que pour les codes de retour. Les coûts en mémoire demeurent importants, évidemment. Elle parle aussi d'une approche de Customizable Throw, soit un throw avec contrôle sur le comportement (unwind? allocate?), un peu comme un new spécialisé. C'est pas bête, ça

Inbal Levi poursuit en examinant les alternatives telles qu'exposées par Herb Sutter et dit favoriser remplacer les types par des valeurs. Elle expose les grandes lignes de cette approche. Enfin, elle discute du texte de James Renwick qui utilise une globale, réduit les états pour le Stack Unwinding et empêche le re-throw

Inbal Levi suggère d'autres avenues : signaler le problème à un autre processus, rapporter le problème sur le Cloud, écrire dans un fichier, utiliser un espace préalloué, sauvegardes des états minimaux, réduire les types à un seul... D'autres options incluent les contrats et std::expected<T,E>

Inbal Levi recommande de séparer la sémantique du mécanisme de son implémentation, puis fait un plaidoyer pour une plus grande place aux systèmes embarqués ou temps réel, qui sont selon elle environ 50% du marché de C++

Inbal Levi pense qu'on devrait faire un Rebase du mécanisme. 

Ça m'a donné des idées : permettre de surcharger throw avec des paramètres supplémentaires, un peu comme on le fait avec new et delete; permettre de spécifier un allocateur pour les exceptions; ... Finalement, c'était intéressant. Inbal Levi n'a pas pris les questions à la fin, par contre.

Bon, c'est à mon tour. Je me dirige vers count_if()...

Vidéo : https://www.youtube.com/watch?v=bMSrNBcir4Y&feature=youtu.be

Patrice Roy – Some Things C++ Does Right

J'ai fait de mon mieux, mais ça a semblé plaire aux gens.

La séance de AMA suit tout de suite après, dans la même pièce.

AMA: Patrice Roy

J'ai eu 25 minutes de questions. Fort sympathique expérience.

Ouf, ce fut amusant; Farbod Ahmadian me dit que les gens avaient l'air contents.

Vidéo : https://www.youtube.com/watch?v=6lurOCdaj0Y&feature=youtu.be

Herb Sutter – Empirically Measuring, and Reducing, C++'s Accidental Complexity ("Simplifying C++" 7 of N)

Herb Sutter dit souhaiter mesurer la complexité. Il la divise entre complexité essentielle (inhérente au problème) et complexité accidentelle (artéfact d'une solution particulière), se basant sur les travaux de Fred Brooks. Il mentionne qu'une porte avec un signe Push dessus est un signe qu'il y a un défaut de conception.

Herb Sutter a probablement le plus riche corps de standards de programmation de tous les langages de programmation, ce qui est une bonne nouvelle (on a des options)... et une mauvaise (on en a besoin).

Herb Sutter a catalogué les conseils de ces guides. Il en a trouvé 533 sur le langage, 84 sur la bibliothèque standard, 11 généraux (pas associés à C++) et 10 complètement fausses, ce qui est en soi instructif (l'erreur peut découler de la complexité). Sur les 533, il en trouve 361 qui sont accidentelles et améliorables; 147 sont essentielles et améliorables (d'autres langages l'auraient aussi); 25 essentielles et trans-langages.

Herb Sutter parle aussi des gains que l'on peut obtenir en améliorant cette situation; il pense que, contrairement à ce que pensait Fred Brooks, on pourrait obtenir un gain de productivité d'un facteur plus grand que 10 en améliorant le langage. Un gros problème, mais aussi une grande opportunité.

Herb Sutter a ensuite découpé les sources de complexité par catégorie; la plus grande est laquo; plusieurs manières de dire la même chose raquo;. Il faut catégoriser empiriquement la complexité de C++ et les opportunités de simplification.

Herb Sutter dit que 23% des conseils touchaient à l'initialisation (7%) et au passage de paramètres (16%). Ça veut dire que les auteurs de guides de style pensent qu'il vaut la peine de se concentrer sur ces aspects.

Herb Sutter montre une table du laquo; comment raquo; passer des paramètres in, out, inout, move, forward. Il pense qu'on devrait spécifier l'intention, pas le comment (il parle de faire de ces cinq mots des mots clés).

Il montre ensuite une série d'exemples (je vous invite à regarder la présentation, c'est intéressant et bien fait). Ses idées reposent sur une analyse de definite first use et de definite last use pour un objet.

Note personnelle : il y a une inefficacité inhérente à certaines applications classiques de out. L'idée n'est pas mauvaise, mais elle n'est pas gratuite. L'idée générale d'exprimer l'intention est très intéressante par contre (surtout si c'est une option qui s'ajoute à l'existant, pour les nouvelles interfaces)

Dans ses exemples, il montre une amélioration de la productivité avec in (plutôt que deux surcharges, une par valeur et une par référence). Ce gain croît de manière géométrique avec le nombre de paramètres

Pour l'intialisation, Herb Sutter propose initialize before use au lieu de always initialize. J'aime bien. Un autre truc dont on parle au comité est de permettre =uninitialized pour avoir des objets délibérément non-initialisés (pas fou; faudrait écrire des constructeurs en conséquence, comme pour le mouvement)

Herb Sutter mentionne qu'un autre 13% des conseils porte sur l'écriture de classes pour ajuster le code (des proxies, par exemple). Selon lui, avec les métaclasses et ses propositions d'aujourd'hui, on pourrait simplifier C++ par un facteur de 30% environ.

Herb Sutter propose l'écriture X& operator=(in X) out; et dit que sa proposition p0708 explique le sens de cette écriture.

Herb Sutter termine en disant que le code est disponible sur github, mais qu'il ne poussera pas p0708 avant que le comité ne puisse en débattre en personne. C'est sage

(Jon Kalb fait le wrap-up du colloque, puis Herb Sutter prend les questions)

Q : Wouldn't ABI stability become even harder if an input parameter can change from pass-by-value to pass-by-reference after changing a field in the `struct` of an argument?

Herb Sutter : oui, c'est possible. Aujourd'hui, on le ferait manuellement cela dit...

Q : How would I tell the compiler that my type is "cheap to copy"? Or tell it I really want in parameters of it to be by value?

Herb Sutter : ... ceci rejoint la question précédente. L'idée est de rendre l'approche opt-in. On pourrait y aller à partir d'un trait avec une valeur par défaut, et le spécialiser pour nos types... Une fonction constexpr serait l'équivalent plus moderne de cette idée. C'est pas encore dans la proposition, mais c'est l'idée qui me vient

Q : How will the parameter description work with inheritance? What if the base abstract method defines an inout and one implementation does not write to the parameter?

Herb Sutter : j'en ai parlé dans la présentation. Il faut que les déclarations corespondent; cependant, si on a une fonction non-virtuelle et qu'on écrit inout, on la laisse telle quelle. Les fonctions virtuelles forment un ensemble ouvert, mais pour un inout, les dérivés ont l'option d'écrire ou pas. Quand on voit tout, on peut constater l'absence de toute écriture et suggérer in par contre (il mentionne qu'il reste des efforts à faire pour clarifier la mécanique avec le code variadique, à titre d'exemple)

C'est pas fini mais je dois quitter pour aller chercher Ludo à l'école et faire le souper. Une chic semaine!

Et après...

Le lendemain du colloque (samedi le 19 septembre), nous avons tenu une rencontre en ligne pour faire une sorte de post-mortem de l'événement et commencer à planifier la version 2020. Nous avons terminé la semaine avec 994 participantes et participants payants, plus encore si nous comptons les bénévoles et les personnes venues exposer leurs produits. Dans les circonstances, c'est remarquable.

Je retourne quelques courriels, et j'ai quelques conférences non-regardées encore dans mon pipeline personnel pressant : la conférence de Ben Deane sur les algorithmes, que je n'avais pas eu l'occasion de terminer (c'est très bon : il parle de strength reduction, ou d'aller chercher l'opération la moins contraignante possible pour réaliser le travail pour accepter une plus vaste gamme de types; tester avec plusieurs types; faire émerger les concepts de l'algorithme est pas le contraire; nommer efficacement; documenter efficacement; quand et pourquoi offrir des surcharges; dans quel ordre placer les paramètres, et en quoi cela influence-t-il l'algorithme; les lois des algorithmes; etc.). Il me reste encore à court terme au moins celle de Stephen Dewhurst (Back to Basics: Class Layout) et celle de Nicolai Josuttis (The Hidden Secrets of Move Semantics). Du plaisir en perspective!


Valid XHTML 1.0 Transitional

CSS Valide !