Quelques raccourcis :
Disclaimer
I wrote what follows mostly to keep my students informed of what a WG21 meeting is like, and I do not want to break the ISO code of conduct (I really don't want to do that!), but I do name people when I don't think it has any harmful effect (when discussions are more heated, I try to refrain from identifying individuals) as it might interest my students to see what kind of argument these bright individuals can formulate. Should you think it would be appropriate for me to remove things from this page, please tell me and I will proceed switfly.
Based on a recent (March 2017) clarification of the ISO code of conduct, I have anonymized all in-meeting discussions except for self-evident things like chairs asking for votes (it's an ongoing process, but I'll fully anonymize it as soon as I can).
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 grâce à Éric St-Jean), j'ai eu le privilège de participer à WG21, le comité de standardisation ISO du langage C++, qui est mon principal outil de travail et d'expression (outre la langue française elle-même). Il s'agit d'un truc prestigieux pour les informaticien(ne)s comme moi, et j'ai l'honneur de faire partie de ce comité depuis la fin de 2014.
Ce qui suit est une sorte de journal de voyage, avec éléments humains et éléments techniques. Ce ne sera probablement pas volumineux, car je serai là en tant que participant plus qu'en tant que « spectateur intéressé », mais j'essaierai de vous donner une idée de l'expérience.
Comme c'est souvent le cas dans les milieux scientifiques, le nom WG21 est peu spectaculaire. On parle ici du Working Group 21, soit le comité de standardisation du langage C++. Pour les informaticien(ne)s, c'est probablement ici que l'explication se suffit à elle-même, étant donné qu'on tombe directement dans leur créneau.
Pour la majorité d'entre vous, par contre, ça reste obscur, alors j'essaie une explication (il se peut que ça ne vous rejoigne pas, mais c'est de bon coeur) :
Le langage C++ existe depuis les années '80. Il a été standardisé par l'organisme ISO en 1998, puis solidifié en 2003 avec des ajustements (relativement mineurs) jugés nécessaires de par l'expérience concrète obtenue depuis C++ 98. Une révision majeure du langage a été ratifiée en 2011, et C++ 11 est l'essentiel du langage par lequel nous exprimons nos idées aujourd'hui. Une révision mineure (mais fort appréciée) a été ratifiée quelques années plus tard (C++ 14), et la première mise à jour majeure à laquelle j'ai activement participé, C++ 17, a été votée à la rencontre de Kona 2017.
Nous travaillerons à WG21 pour les prochaines années sur C++ 20, de même que (pour la présente rencontre) sur des correctifs idéalement mineurs à C++ 17. Les objectifs de C++ 20 sont très ambitieux, et font saliver les gens qui, comme moi, cherchent à tirer le maximum de ce que ce langage a à offrir. Certains des éléments les plus importants que nous souhaitions voir intégrés au langage à partie de C++ 17 ont dû être retardés pour diverses raisons, et nous souhaitons les voir faire partie d'un C++ 20 de grande envergure.
On me dit que nous sommes ≈300 membres de WG21 sur la planète, et qu'environ cent personnes se présentent aux rencontres du comité (les autres font surtout des contributions par écrit). Pour la rencontre documentée ici, nous serons environ 120.
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 en relief, comme celui-ci. Si vous ça ne tombe pas dans vos cordes, passez par-dessus.
Sur le plan de la procédure, certains débats étant chauds et les gens qui débattent étant mes pairs, je vais m'abstenir de donner dans le nominatif dans ces sections (à moins que ça n'ait pas d'incidence).
Fin du contenu technique
Le secrétaire des rencontres du comité, Jonathan Wakely, sera absent cette fois, étant récemment devenu papa. J'ai offert de le remplacer, ce qui me fera vivre une expérience... différente.
train tôt. Merci Za pour le lift.
Gare à 8 h 22. Embarquement 8 h 25. Chiens renifleurs.
Classe affaires (bon rabais, moins cher que la classe Économie Plus). Bon service, repas de Chow Mein végétarien avec un verre de rouge qui allait bien avec le dessert végan aux pommes. Je lis une bonne partie des nombreuses propositions dont nous discuterons cette semaine, et je trouve quelques irritants; je profite du WiFi pour contacter les auteurs. C'est bien pratique. Ma voisine de siège travaille pour un organisme de charité à Montréal, mais va voir son garçon, un sportif qui s'est déchiré le talon d'Achille et qui a de la difficulté à se cuisiner des petits plats.
Gare Union au centre-ville de Toronto. Tout est en réparation, dans la gare et dans les rues. C'est pas dépaysant quand on arrive de Montréal.
Je marche vers mon hôtel, le Chelsea. Plein centre-ville, ça se fait à pied de la gare en un peu moins d'une demi-heure. Il pleut légèrement. Pas mal de monde dans les rues. L'architecture est jolie.
À l'hôtel, longue file pour le check-in; je suis arrivé juste après un autobus de touristes. Une demi-heure d'attente environ.
Ma chambre est au 23e étage. Assez grande, mais pas de frigo (j'aime bien garder un peu de bière à la chambre pour les longues soirées de travail, normalement). Je suis supposé aller rejoindre Guy Davidson, un collègue de SG14 que je vois dans d'autres occasions, mais pour qui ce sera le premier WG21. Il est au Sheraton, à mi-chemin entre la gare et mon hôtel.
Je me couche un peu et je tombe endormi. Heureusement, ma belle Za et les plus jeunes m'appellent sur Skype et me réveillent. Je bavarde un peu avec eux, Za et moi convenons de regarder Twin Peaks en simultané ce soir (bonne idée; j'étais triste de ne pas le voir avec elle ce soir), puis je vais rejoindre Guy Davidson pour une bière et une jasette sur une de ses propositions (il en est à la version 4, et aimerait que ça passe, mais il reste – selon moi – deux ou trois irritants mineurs et un plus important pour lesquels il vaut mieux préparer un plan B) tout comme sur le déroulement de la semaine qui s'annonce. Agréable et sympathique.
Je reviens vers ma chambre. Pas moyen de trouver de quoi prendre un verre en regardant l'émission : nous sommes au centre-ville mais il n'y a plus de commerce ouvert vendant de l'alcool. L'hôtel ne permet pas d'aller prendre un verre au bar et de l'apporter avec soi (ils insistent pour passer par le service aux chambres, mais c'est dispendieux!) alors tant pis. Je me prends un sandwich pas cher dans un commerce non-loin et je reviens travailler un peu.
Dans le lobby, je croise Paul Preney, puis Ville Voutilainen qui vient bavarder et semble d'excellente humeur. Nous planifions nos déplacements pour demain (Paul Preney est un habitué des lieux), puis je retourne à ma chambre manger mon sandwich et pousuivre mes lectures.
Après une pause Twin Peaks avec mon amoureuse (malgré la distance), c'est l'heure du dodo, car la journée de demain s'annonce immense...
Debout vers 5 h, douche, recherche d'une source de café (il y a du café en sachets, un peu comme des sachets de thé; j'ai des appréhensions, mais c'est pas si mal finalement). Je prends les messages du matin, et je constate que pour une rare fois, je suis l'un de ceux qui ne vivent pas le décalage horaire (mais beaucoup en souffrent!).
Préparation des documents. Expliquer comment j'ai procédé. Gros merci à Jonathan Wakely.
Petit coucou à Ludo qui dort.
Marche avec Paul Preney vers le bâtiment où nous travaillerons cette semaine. Une vingtaine de minutes, agréable. Le secteur, universitaire, est évidemment très beau. Nous sommes passés devant la législature ontarienne à Queen's Park, un endroit magnifique (comme il se doit).
Plénière (à venir; j'étais secrétaire alors j'ai des notes formelles, mais je dois les épurer)
Nous sommes dans la salle 1170. À la fin de la plénière, Bjarne Stroustrup fait remarquer que la fin du développement du langage C et le début du développement du langage C++ se sont tous deux faits sur un ordinateur 1170, ce qui a un petit côté romantique.
Nous sommes répartis à plusieurs endroits dans l'université. CWG loge dans un bâtiment adjacent au bâtiment « principal » où sont la plupart des groupes de travail; SG1 loge au premier étage, mais on utilise aussi leur local pour les pauses café et la prise de présences. EWG garde l'auditorium principal, évidemment (ou peut y loger environ 130 personnes, donc quand nous sommes tous ensemble c'est assez plein), mais les séances de soirée seront dans un local distinct où la capacité est plus proche de 60-70 individus, alors il vaudra mieux arriver à l'heure. Nous tiendrons des séances de soirée aujourd'hui (organisation de WG21 et règles de conduite, une poursuite de la séance en ce sens à Kona), demain (concepts et modules; ce qui débordera des travaux de la journée, car ce sont de très gros morceaux) et jeudi (réflexivité). Il n'y aura pas de séance mercredi dû au souper protocolaire à la Tour du C.N.
Muffin, signature, quelques salutations, CWG.
Je tiendrai le Wiki en début de séance car Jens Maurer sera à EWG. Mes notes seront donc embryonnaires.
Les travaux commencent vers 10 h 15.
Gor Nishanov explains the issues and the proposed resolutions
No opposition for proposed resolution to issue 2
No opposition for proposed resolution to issue 6
No opposition for proposed resolution to issue 7
For issue 8, Hubert Tong recommends reject since NAD. Agreed.
Issue 18 is editorial
Issue 21 involves some discussion on wording. Davis Herring makes suggestions and remarks a missing p.
Davis Herring asks what the return type of p.return_void() is
Gor Nishanov says we have not expressedly said it had to be void
Richard Smith mentions that this is a comma expression, which could be annoying with an overloaded operator comma
Davis Herring thinks this might not be a problem if return_void() is of type void
Richard Smith suggests inserting (void) in the statement. Davis Herring suggests explicitly stating that it returns void
Gor Nishanov will process this offline. Roger Orr offers to help with wording
Issues 3, 5 and 17 suggest rebasing on C++ 17. Gor Nishanov suggests rejecting for the moment, to avoid redundant work if something happens (it's too soon)
Mike Miller asks to see the text for issue 21 again once it's done
Jason Merrill suggests we word this in terms of reference bindings
Nathan Sidwell wonders if we need to perform overload resolution on the name
Jens Maurer revient vers 10 h 50 et je lui passe le Wiki.
Richard Smith tente une formulation pour couvrir le cas volatile (on veut const, const&, mais pas & ou volatile ou volatile&). Patrice Roy fait remarquer que la formule devient complexe à digérer dans le cas const volatile&. On cherche une tournure qui ne soit pas indigeste.
Davis Herring se dit surpris que le mot clé volatile intervienne ici, du fait que normalement, ajouter cette qualification accroît l'ensemble des cas d'utilisation. Mike Miller y comprend plus un lien vers la création implicite de temporaires, qui ne s'applique qu'à const.
Dinka Ranns suggère de remplacer simplement cv-qualified par const. Ça aide à la lecture un peu. Davis Herring remarque qu'on a un if...then...unless, qui « ne coule pas nécessairement bien » à la lecture. Jens Maurer prend en note une proposition de formulation car Richard Smith et Jason Merrill ont dû aller chez EWG pour discuter de template deduction. Davis Herring va faire une mise à jour rapide pour dépanner.
Tiré du texte :
« In a nutshell, the proposal with the most consensus was to support
struct S {
int x : 5 = 42;
};
with the proviso that parsing ambiguities such as
int a;
struct S2 {
int y : true ? 1 : a = 42;
int z : 1 || new int { 42 };
};
are resolved with a max-munch rule »
Jens Maurer trace un historique du dossier. Présentement, dans la grammaire, l'endroit où nous avons la définition des tailles des bitfields ne permet pas d'utiliser l'affectation. Quand il y a ambiguïté, on peut utiliser les parenthèses :
int a;
struct S2 {
int y : (true ? 1 : a) = 42; // oui, a n'est pas constexpr mais n'est pas évalué, et on met 42 dans un bitfield de taille 1...
int z : (1 || new int) { 42 }; // même principe... >soupir!<
};
C'est un ajustement grammatical plutôt inhabituel, mais c'est aussi pour un mécanisme un peu obscur. L'exemple complet est :
int a;
const int b = 0;
struct S {
int x1 : 8 = 42; // OK; "= 42" is brace-or-equal-initializer
int x2 : 8 { 42 }; // OK; "{ 42 }" is brace-or-equal-initializer
int y1 : true ? 8 : a = 42; // OK; brace-or-equal-initializer is absent
int y2 : true ? 8 : b = 42; // error: cannot assign to const int
int y3 : (true ? 8 : b) = 42; // OK; "= 42" is brace-or-equal-initializer
int z : 1 || new int { 0 }; // OK; brace-or-equal-initializer is absent
};
Patrice Roy lance à la blague « Learn to code with the Core Working
Group »
. On se bidonne.
On amène ça pour un vote samedi.
Davis Herring a fait une mise à jour du document. C'est simple et ça évite le piège de discuter de volatile.
On amène ça pour un vote samedi.
Hubert Tong demande qu'on en parle avant de l'amener pour vote. C'est une question de transtypage applicable ou pas à un glvalue (objet temporaires, expressions temporaires, extension de vue), et de terminologie pour s'assurer qu'on lie (bind) correctement aux objets ainsi synthétisés.
C'est un dossier de complexité non-triviale. On va prendre le temps d'y réfléchir.
Certains échanges plus confidentiels s'ensuivent.
Par la suite, Hubert Tong signale un irritant avec reinterpret_cast et le concept de Pointer-Interconvertibility, mais le document le décrivant a un problème de formatage. Il nous arrange ça et on y reviendra ensuite.
Nous fermons de 12 h à 13 h 30 car les sources de nourriture ne sont pas très proches (rien de grave, mais il faut marcher quelques coins de rue et revenir et ça prend un peu de temps). Il est supposé y avoir des Food Trucks pour les étudiant(e)s de l'université, mais je ne suis probablement pas allé dans la bonne direction car je ne les ai pas trouvés. Pas grave, Tim Horton's était à la rescousse, et je n'ai à peu près pas de budget alors ça a fait le boulot.
À mon retour, Jens Maurer était en train de répondre aux questions d'une journaliste, mais expliquer ce qu'on fait n'est pas nécessairement simple. Chris Szalwinski revient ensuite bavarder avec Jens Maurer et moi-même; nous ne le connaissions pas, mais il enseigne à l'université de Toronto et s'intéresse à ce que le comité fait. On lui explique un peu comment ça fonctionne, et on essaie de voir avec lui où il serait plus heureux, car CWG, même si j'adore personnellement, c'est pas pour tout le monde.
Truc amusant : la plupart des gens qui ont trouvé les Food Trucks sont
revenus... avec de la poutine
On reprend les travaux vers 13 h 30.
Thomas Köppe vient nous rejoindre avec deux propositions.
Thomas Köppe nous explique qu'EWG aime et souhaite le faire passer tel quel si la terminologie tient la route.
Davis Herring demande si on procède avec une dépréciation de certains trucs qui seraient moins pertinents à partir de maintenant. Thomas Köppe dit que c'est pour une proposition future.
On amène ça pour un vote samedi.
Le texte existant est bien, mais Faisal Vali l'a implémenté et avait des questions, par exemple : ##__VA_OPT__ devrait-il faire une concaténation des paramètres ou encore devrait-on utiliser __VA_OPT__ comme un bloc indivisible?
On discute pour voir quelle(s) direction(s) on compte prendre. Le mécanisme sera aussi appliqué au langage C, qui l'a reçu favorablement. Je n'ai pas tout pris en note, car j'évite les macros le plus possible, mais ces mécanismes vont aider à la rédaction de meilleures macros variadiques.
On amène ça pour un vote samedi.
Jens Maurer a retravaillé le texte sur la base des suggestions de Hubert Tong. On introduit entre autres une mention des effets des transtypages du langage C, mais il se trouve que le standard de C++ traite très peu de ces derniers alors on n'est pas trop certains du texte.
On est satisfaits de ce que ça donne. Jens Maurer va en faire une proposition officielle et l'amener pour un vote samedi.
Ceci est devenu valide :
struct A { int n; } a;
int *p = reinterpret_cast<int*>(&a); // ok, a and a.n are pointer-interconvertible
int m = *p; // ok, p points to a.n
... mais ceci ne l'est pas :
int &r = reinterpret_cast<int&>(a);
int n = r;
Faut arranger ça. L'air de rien, la terminologie pour parler de l'extension de la vie de références accédées par voie d'interconvertibilité de pointeurs est... délicate.
Richard Smith pense que ça ne va pas assez loin, et qu'on devrait avoir un support des cv-qualifications en plus (accepter les gains de qualifications, évidemment; pas les pertes). Effectivement, ce serait une bonne idée. Il y aura un rapprochement entre les deux points de vue.
Il y a beaucoup de questions ici, même s'il y a un réel besoin. On revient à EWG avec ces questions. En gros, avec ceci :
struct X {
template X* alloc();
template static X* adjust();
};
template template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
namespace N {
struct A { };
template <typename T>
T func(const A&);
}
void g() {
N::A a;
func<int>(a); // ill-formed: < means less than
template func<int>(a); // OK: < starts template argument list // ce serait l'idée nouvelle
}
... le < dans func<int> pourrait être un opérateur d'onrdonnancement. Il nous faut une règle. On discute plus d'une demi-heure, mais l'avenue la plus prometteuse serait de faire un using local pour indiquer qu'ils'agit d'un type à droite de l'opérateur <.
Jens Maurer pense qu'il serait sage de la faire passer entre les mains d'EWG à nouveau, avec nos suggestions.
On apprend que la séance de ce soir sera à la salle de plénière, 1170. On présume que Michael Wong a réussi à faire une acrobatie administrative pour nous permettre d'occuper une plus grande salle que prévu.
C'est une proposition qui nous revient car elle a été discutée, mais en téléconférence seulement.
On trouve une faute mineure, à corriger éditorialement. On suggérera à LWG de le porter pour vote samedi.
On prend une pause vers 15 h 30. Je jonglais avec un truc inspiré d'un des dossiers que l'on a débattus aujourd'hui, et ce que mes tests me donnaient me rendaient curieux quant aux raisons :
Test 00 | Test 01 | Test 02 |
---|---|---|
|
|
|
a |
|
|
Je m'attendais à ce que le test 02 soit ambigu. J'en ai parlé avec quelques collègues, et il semble que dans la liste des règles à appliquer, celles du Core Language (qui s'appliquent au tableau brut) passent avant celles s'appliquant aux types « usagers » comme std::pair<K,V>. Ceci se confirme en remplaçant int(&&)[2] par std::array<int,2>&& ce qui devient ambigu. Intéressant.
Je bavarde un peu avec Aaron Ballman, toujours sympathique. Semble qu'un de ses collègues soit venu à ma présentation au C++ Users Group de Montréal il y a deux semaines. J'espère qu'il a apprécié!
Jens Maurer explique que SG1 souhaite décrire les contraintes applicables aux calculs vectoriels pour permettre les opérations SIMD, ce qui entre... profondément dans le territoire de CWG avec les définitions de trucs comme sequenced-before par exemple. Ce document vise la TS sur le parallélisme.
Pablo Halpern nous explique en mots l'étendue des dépendances inter-itération possibles (en gros, on peut dépendre de manière restreinte sur les itérations précédentes, mais pas sur les itérations subséquentes). C'est extrêmement délicat, car on définit l'ordre dans un même énoncé ou dans deux énoncés distincts entre lesquels il n'y a pas d'énoncé tiers, le tout formellement.
Richard Smith souligne la difficulté de comprendre la relation dans un cas comme a+=b; sur la base du texte proposé.
Davis Herring parle de cas tels que MPI où il n'y a pas nécessairement d'ordre entre deux opérations (unspecified), et trace un parallèle avec certaines options d'optimisation à la portée des compilateurs. Richard Smith suggère de laisser certains ordres unspecified, mais d'ajouter que dans un tel cas, il faut qu'ils soient cohérents (consistent).
Jens Maurer dit comprendre l'intérêt de mieux définir contains au sens des opérations.Davis Herring pense que si on peut définir un ensemble de règles qui préviendraient un réordonnancement « hostile » des opérations, bien qu'on ne sache pas quelles sont ces règles, alors nous aurions une solution; après tout, si nous faisions les calculs en séquence, il n'y aurait pas de problème. Pablo Halpern se dit assez d'accord avec cette lecture. John Spicer souligne qu'on pourrait définir les règles dans le cas des opérateurs surchargés, pour garder de la latitude aux optimiseurs dans le cas des primitifs.
On vogue vers quelque chose comme consistent-indeterminately-sequenced pour laisser une certaine liberté à l'optimiseur. Jens Maurer pense toutefois qu'il serait sage d'éviter de laisser cette proposition teinter le texte du Core Language, et de construire le vocabulaire vectoriel à une certaine... distance, disons, de cette partie du standard. La définition de contains, au sens où une sous-expression est contenue dans une expression composite, mérite un peu de travail pour éviter de trop inclure (destruction des temporaires, appels de fonctions).
Pablo Halpern indique qu'il trouve difficile de définir ce comportement car les compilateurs font déjà « la bonne chose », mais Davis Herring mentionne qu'on cherche à prévenir des tentatives, de la part des compilateurs à venir, d'être trop intelligents et de tout casser.
Aaron Ballman suggère qu'on tienne compte des cas de code machine insérés inline, et pense que l'acceptation d'un goto interne à un bloc mais le rejet d'un throw...catch s'avère trop restrictif. Pablo Halpern explique qu'une levée d'exception est un événement dynamique, runtime, alors qu'un goto est un événement statique, compile-time. Selon lui, si nous permettions de calculer les adresses dynamiquement pour un goto, alors il faudrait aussi interdire ce mécanisme.
Dinka Ranns pense qu'on devrait retravailler un peu la définition du mot evaluation, quitte à faire une liste de puces. On travaille un peu le texte. On va peut-être s'en sortir avec des virgules sagement placées.
On met cette proposition de côté le temps qu'elle soit retravaillée.
On attend Louis Dionne. Mike Miller en profite pour vérifier qui parmi nous compte aller à la session conjointe entre CWG et EWG demain sur les concepts et sur les modules. Il semble que l'on n'aurait pas quorum si nous tenions une rencontre de CWG isolément.
Hubert Tong pense qu'on ne devrait pas laisser de λ dans un sizeof. Selon lui, à ce stade, il reste encore trop d'interactions possibles pour ce qui est des captures, et cela donnerait un comportement observable. Aaron Ballman suggère qu'alignof tombe dans la même catégorie. On en discute car tous ne sont pas convaincus de la difficulté; on va attendre avant de trancher. Richard Smith pense que decltype est aussi touché, mais pas typeid.
Faisal Vali pense que la disposition en mémoire d'une λ ne sera pas différente dans un contexte non-évalué que dans un contexte « traditionnel ».
On explique la situation pour ce qui est des correctifs apportés dans cette version de la proposition. On discute ensuite de la distinction de type entre plusieurs occurrences syntaxiquement identiques d'une λ. Richard Smith trace un parallèle avec les struct anonymes, qui sont toutes différentes les unes des autres et qu'on gère bien, mais Hubert Tong craint que les types des fermetures, différents pour chaque instanciation, ne pose problème.
La question est de savoir si deux occurrences de ceci dans une même unité de traduction sont identiques ou pas :
template <class T>
void f(T, decltype([]{ return 0; }()));
Ici, la réponse est oui car le type du deuxième paramètre est int. Par contre, avec ceci :
template<class T>
void g(decltype([]{}) (*) [sizeof(T)]); // la taille du tableau est dépendante de T; le type de retour est le type d'une λ
On a un irritant ici car le linkage des types influence le code généré et les signatures de fonctions exposées à l'éditeur de liens. On constate par contre que le type décrit par decltype, lui, n'est pas dépendant. On se questionne ensuite sur :
void g(decltype([]{})); // qu'en est-il de ceci?
Ceci semble moins risqué que les cas où la λ serait dépendante d'un type générique. On discute encore un peu et on arrive au constat que si on parvient à conserver un internal linkage pour la λ, on va s'en sortir sans introduire du mangling supplémentaire. Richard Smith mentionne que ça va devenir croustillant avec la TS des modules.
On doit arrêter pour cet après-midi, car il est déjà 17 h 37.
Faudra continuer de réfléchir à ceci, soit demain (si la séance conjointe entre CWG et EWG est plus courte que prévu), soit plus tard.
J'ai accompagné un groupe de gens qui ont entendu l'appel du toujours sympathique Roger Orr. Nous sommees allés manger une bouchée (un pub à 15-20 minutes de marche du lieu où nous travaillons). Correct : j'ai pris une salade (l'assiette était plus grosse que je ne l'aurais cru) et une bière en fût (à l'oeil, un degré d'alcool d'environ 4%). Ce fut chouette de parler un peu avec des amis comme Aaron Ballman, Davis Herring et Billy Baker. Cela dit, la rencontre de soirée débutait à 19 h 30 alors il a fallu revenir rapidement.
La rencontre de soirée porte sur la gestion de WG21 et la progression du langage en tant que tel. C'est un peu trop politique pour que je tienne un pseudo-verbatim ici sans contrevenir aux règles en vigueur, mais ça a trait à P0684R0. Nous avons discuté du futur de nos pratiques : comment encourager l'évolution du langage, la modernisation du code, l'adoption des nouveaux outils et la mise au rancart éventuelle de ceux qui sont désuets ou dangereux.
Il nous fallait un secrétaire, et la salle était pas mal pleine. Vu que j'ai tout ce qu'il faut avec moi et que je commence à comprendre la mécanique, j'ai pris les rennes. Je vous passe donc les détails, mais :
C'est un sujet chaud, et on a parlé fort jusqu'à 21 h 30
Je suis retourné à ma chambre. Regardé une émission à distance avec ma belle. Dodo.
Lecture. Croisé Michèle Audette dans le hall, j'ai pu lui parler un peu (fort sympathique) et la remercier pour son superbe travail. C'est drôle : elle ressemble un peu à ma soeur physiquement (mais en plus grand), et je l'ai vue à la télé (l'émission Le beau dimanche du 9 juillet, que j'ai regardé en diagonale en travaillant) alors j'ai réagi comme si je la connaissais, et elle aussi. Drôle de rencontre.
Marche avec Paul Preney. Pas de sous (1,08$), zut. Banque cool.
Session conjointe CWG et EWG ce matin, portant sur le chaud et politique sujet des modules.
On commence vers 8 h 35. Nous examinerons deux propositions concurrentes ce matin, soit une par Nathan Sidwell et une par Gabriel Dos Reis.
Nathan Sidwell dit qu'il a écrit le texte, mais que les idées viennent d'une conversation avec Gabriel Dos Reis et Jason Merrill. Sa proposition vise à inscrire de manière syntaxique l'existence d'une interface et d'une implémentation de module. Au moins deux approches sont possibles, dont un par annotation :
module M [[interface]];
...ce qui consomme un mot clé (interface) qui ne peut plus être utilisé dans d'autres contextes, par exemple dans les macros comme on le fait dans COM, et une syntaxe « première classe » :
export module M;
... qui a de bons côtés mais a plus de conséquences pour la grammaire.
Gabriel Dos Reis dit que la forme syntaxique simplifie le problème à plusieurs égards. Des expérimentations ont été tentées dans MSVC et gcc. Gabriel Dos Reis parle de commentaires... violents, de la part des usagers. Les gens ont une réaction... viscérale, pour tout ce qui touche à la syntaxe.
Richard Smith demande si les objections venaient de gens qui utilisent les modules au quotidien. Gabriel Dos Reis dit qu'il y avait des réactions par deux catégories de gens, vraiment, soit des utilisateurs réguliers et des gens moins impliqués.
On demande s'il y a une correspondance avec le modèle Java d'une classe publique, un fichier. Nathan Sidwell explique que le modèle des modules est différent, avec un fichier d'interface pour plusieurs fichiers d'implémentation. Gabriel Dos Reis rappelle qu'on cherche à clarifier la syntaxe, pas à modifier le design.
Gor Nishanov fait une distinction entre la fonctionnalité (exporter des éléments d'un module) et l'esthétique. Nathan Sidwell pense que l'exposition d'une interface pour un module ne devrait pas être optionnelle. Gor Nishanov fait remarquer que la grammaire proposée admet des annotations (optionnelles, bien sûr). Daveed Vandevoorde se dit heureux de la proposition, qui évitera une fragmentation en dialectes si elle est acceptée.
David Sankel a remarqué, en examinant le code de son entreprise, que le cas « typique » serait probablement de remplacer une paire .h et .cpp par un seul et même module. Nathan Sidwell pense qu'on verra principalement une fragmentation en plusieurs implémentations pour une même interface. Gabriel Dos Reis dit que l'expérience d'implémentation dans son entreprise a montré que pour eux, certains .h (surtout avec des templates) devenaient un seul module, et d'autres se trouvaient à être répartis en plusieurs implémentations. Il semble que des mots comme import et export entraînent une réaction chez certaines programmeuses et certains programmeurs; le consensus semble être d'annoter soit l'interface, soit l'implémentation, mais pas les deux. Annoter l'interface semble être la tangente la plus prometteuse.
Ville Voutilainen demande ce que Nathan Sidwell souhaite obtenir comme orientation de la part de l'assemblée. Nathan Sidwell veut savoir s'il peut aller devant CWG avec sa proposition de rendre export obligatoire pour les interfaces des modules. La réponse est très favorable.
Gabriel Dos Reis prend le plancher. L'idée de partitionner les modules est de permettre de relaxer le requis de placer une interface de module dans un seul fichier. L'idée est d'annoter l'interface par [[partition]], et d'exiger que toutes les partitions soient compilées ensemble.
Daveed Vandevoorde demande s'il y a un ordre entre les partitions, mais Gabriel Dos Reis répond par la négative, du fait que cela nuirait à la compilation en parallèle.
Richard Smith rappelle qu'il est aussi possible pour chaque partition d'expliciter ce dont elle dépend. Gabriel Dos Reis pense qu'il est préférable (et plus rapide) d'éviter cette avenue.
John Lakos dit que l'ordre dans lequel apparaissent les énoncés dans un fichier source est important, et voit un parallèle avec le recours à un graphe de dépendances. Gabriel Dos Reis estime préférable de ne pas placer ces considérations sur les épaules des clients.
Jason Merrill demande quel est l'intérêt d'avoir plusieurs partitions si elles ne dépendent pas l'uine de l'autre. Gabriel Dos Reis dit qu'elles ne sont pas totalement indépendantes (elles peuvent introduire une dépendance entre deux noms, par exemple).
Richard Smith demande des précisions sur la pratique de Tag Parsing que Gabriel Dos Reis recommande d'implémenter pour réaliser un prétraitement rapide des fichiers. Gabriel Dos Reis donne quelques détails. Richard Smith explique pourquoi il trouve cela restrictif, mais il semble y avoir une incompréhension entre les deux. Duncan Exxon-Smith craint que cette approche de passe pas le test de l'échelonnabilité. Gabriel Dos Reis précise qu'il ne veut pas éviter les dépendances, car cela ne tiendrait pas la route pour des systèmes autres que ceux de petite envergure, mais souhaite éviter celles qui, selon lui, de devraient pas exister. Duncan Exxon-Smith demande de préciser ce que cela signifie. Gabriel Dos Reis explique sa pensée, parlant entre autres de code qui dépend d'un fichier source plutôt que de son interface. On a ensuite un débat, à savoir s'il est préférable de simplifier la vie aux programmeuses et aux programmeurs, ou s'il est préférable de rendre leur processus de développement plus prévisible. Certains pensent que les dépendances complexes devraient être logées dans un même fichier source, alors que d'autres estiment que ceci n'est pas une pratique recommandable du fait qu'elle peut mener à des fichiers sources de grande taille.
Daveed Vandevoorde exprime des réserves face au Tag Parsing, qu'il estime fragile et considère susceptible de briser et de générer des diagnostics de piètre qualité. Gabriel Dos Reis dit qu'une partition de module n'est pas, en soi, une interface de module. Une discussion technique s'ensuit sur les impacts du Tag Parsing, par laquelle il devient possible de traiter du code malformé pendant une longue période, essentiellement en pure perte : simplement manquer une accolade peut transformer un nom local en nom global.
Richard Smith se dit d'avis que les partitions servent surtout à éviter que les gens ne construisent leurs interfaces avec des #include. Il craint que ce qui est mis de l'avant ne donne pas les résultats attendus. Roger Orr rappelle qu'une fois un module compilé, on se fout un peu de la séparation ou pas d'une interface en partitions. On demande quel est l'intérêt des partitions dans l'optique proposée ici. Gabriel Dos Reis rappelle que les programmeurs aiment travailler en petits compartiments. Chandler Carruth dit que ses programmeurs aiment définir des relations complexes entre plusieurs fichiers; il pense qu'on ne devrait pas les juger, quelle que soit notre position personnelle sur le sujet. Hal Finkel se dit faiblement en faveur de dépendances exprimées plus explicitement; il poursuit en discutant de Tooling, et dit que toute décision prise par un outil de manière à ajouter des trucs dans un fichier source ou dans un fichier binaire devrait être tel que les programmeuses et les programmeurs détermineront le point d'insertion.
David Sankel aime la composabilité des modules, mais craint toute décision qui aurait pour impact d'en éloigner les gens.
Gor Nishanov dit qu'on peut toujours découper l'implémentation d'un module en plusieurs fichiers, et pense que la partition d'une interface est une expérimentation allant dans le même sens.
John Spicer est en faveur de dépendances exprimées explicitement. On ne sait pas comment les gens travaillent dans chaque entreprise; selon lui, leur imposer un autre mécanisme serait périlleux, du moins sans avoir fait un peu de recherche au préalable. Bjarne Stroustrup dit avoir de la difficulté à comprendre le rôle des partitions, et en est venu à les voir comme une sorte d'optimisation du temps de compilation. Il dit souhaiter éviter que les gens ne commencent à importer des modules gigantesques (il trace un parallèle avec <windows.h>) pour se « simplifier la vie ».
Nathan Sidwell indique que les dépendances entre les modules sont un graphe acyclique, mais Gabriel Dos Reis dit qu'il ne faut pas voir ce mécanisme comme un outil pour briser des cycles. Nathan Sidwell estime que le problème que nous cherchons à résoudre ici n'est pas clairement défini.
Chandler Carruth rappelle que Google a tenté l'expérience des modules, bien qu'avec une syntaxe différente. Il est disposé à présenter ses résultats (vitesse de compilation, souplesse de développement, ce genre de truc) mais pas dans une proposition formelle, car cela comprend des informations de nature confidentielle (il ne veut pas que ce soit découvrable par des moteurs de recherche que nous ne nommerons pas).
David Sankel pense que les gens
qui veulent programmer tout croche devraient avoir de la difficulté à y
arriver. Il ne ferait pas d'acrobaties pour faciliter la pérennité de leurs
pratiques. Dans ses mots, « What is ugly shoud look ugly »
.
Davis Herring dit qu'avec le Tag Parsing, si une partition expose un type incomplet consommé par une autre partition, alors il faut tout traiter pour savoir les détails des différents types. Un échange s'ensuit, car il y a des désaccords dans la salle, mais Daveed Vandevoorde pense que pour des raisons d'efficacité, on voudra réaliser une collecte d'information pendant le Tag Parsing, et qu'une connaissance des types entiers est requise pour y arriver. Chandler Carruth dit qu'un cas d'utilisation a été présentéa à Jacksonville (février 2016), supportant des partitions avec dépendances cycliques, et il est d'avis qu'on devrait les permettre. John Spicer se dit d'avis que le rôle des partitions de modules est d'organiser le code, pas d'accélérer la compilation.
Bjarne Stroustrup entend deux raisons pour les partitions dans la salle. Il pensait que les partitions n'étaient qu'un mécanisme d'optimisation, et se dit confus. Il se demande à quel ordre de magnitude il devrait placer sa réflexion : quelle est l'envergure, en termes de taille, d'un module ou d'une partition? John Spicer pense que ce sont nos usagers qui vont déterminer cette envergure, et pense que les partitions sont une bonne solution à ce problème.
Jason Merrill demande si on peut voir les partitions comme un moyen d'automatiser les déclarations a priori. Ça ne semble pas très loin de la réalité. Chandler Carruth revient sur les dépendances cycliques, un cas d'utilisation, et sur les bibliothèques « parapluies » qui ont une interface de très grande surface. Il faut selon lui supporter les deux, et probablement d'autres. Gabriel Dos Reis dit que certains usagers de gros en-têtes tels que <windows.h> voudront conserver l'ancien modèle pour des raisons techniques.
Ville Voutilainen estime que le temps est venu de prendre des votes. Le premier porte sur l'intégration de la partie de D0584R1 qui porte sur les partitions de modules dans le PDTS des modules. Botond Ballo se questionne sur le sens du vote et demande des précisions. Le vote est défavorable.
Herb Sutter dit que les NB nous indiquent vouloir des partitions, donc même si on souhaite un vote sur l'adoption ou non de partitions, il ne sait pas comment nous pourrions interpréter le résultat du vote. Il semble qu'un mécanisme a eu droit à un vote favorable à Jacksonville mais n'est pas encore inclus dans le PDTS; cependant, il y a une forme de confusion sur le résultat dudit vote. Hal Finkel estime qu'il nous faut expérimenter sur une masse de code importante pour se faire une tête, mais Ville Voutilainen rappelle que nous ne pouvons pas expérimenter avec un mécanisme qui n'a pas été adopté.
Le second vote est pour savoir si le PDTS sur les modules doit supporter des partitions. Bjarne Stroustrup se dit certain que les partitions seraient utiles, mais pense que les modules rapporteraient des bénéfices même sans partitions. Herb Sutter dit que, si jamais nous ne parvenons pas à une solution cette semaine pour le problème des partitions, il souhaite que le vote soit pris à nouveau. Le vote est défavorable.
On prend une pause tardive vers 10 h 40.
Pause. Bavardage avec Andrew Pardoe, qui parle bien français, et avec Jonathan Caves.
Les travaux reprennent vers 11 h 10
Nathan Sidwell reprend le plancher pour discuter du cas suivant :
// Foo interface TU
export module Foo;
namespace bill {
export void X (int);
};
// Bar interface TU
export module Bar;
import Foo; // non-reexport
export using bill::X;
// User 1 TU
import Bar;
... X ... // #1 What is found?
import Foo;
... X ... // #2 What is found?
// User 2 TU
import Foo;
La préoccupation soulevée par cette proposition est de déterminer ce qui se passera dans un tel cas.
Richard Smith fait une distinction entre contrôler l'exposition des noms et contrôler l'exposition des entités. Cela dit, l'exemple est bien choisi et porte à réflexion. Davis Herring dit que le nom ne peut, dans user1.TU, être compris que comme étant dans l'espace nommé global, à moins bien sûr que Foo ne soit importé. Gabriel Dos Reis dit que l'on n'a rien fait d'autre ici que d'exposer un nom, et qu'on ne peut vraiment rien faire avec à ce stade.
Un consensus semble se dégager. Gabriel Dos Reis remercie Nathan Sidwell d'avoir trouvé cet irritant.
Richard Smith propose un autre exemple :
// Foo interface TU
export module Foo;
namespace bill {
export struct X {
int n;
};
};
// Bar interface TU
export module Bar;
import Foo; // non-reexport
export using bill::X;
// User 1 TU
import Bar;
... X ... // #1 What is found?
X x; // Ok?
int n = x.n; // Ok?
import Foo;
... X ... // #2 What is found?
// User 2 TU
import Foo;
On se demande si le seul nom Foo.bill::X est importé dans Bar (en tant que X dans l'espace global) ou si la classe entière l'est.
La question est de savoir ce que signifie export using bill::X; en fait. Est-ce une exposition du type en tant que type incomplet? Roger Orr soulève qu'il serait très préoccupé si ce qui suit devait fonctionner :
// Foo interface TU
export module Foo;
namespace bill {
export struct Wiggle {};
export struct X {
Wiggle n;
};
};
// Bar interface TU
export module Bar;
import Foo; // non-reexport
export using bill::X;
// User 1 TU
import Bar;
... X ... // #1 What is found?
X x; // Ok?
auto n = x.n; // Ok?
import Foo;
... X ... // #2 What is found?
// User 2 TU
import Foo;
... du fait que nous viendrions d'instancier un type qui n'a jamais été importé. On se demande comment un module comme Bar pourrait exporter convenablement Foo.bill::X, et plusieurs sont d'avis qu'il faudrait alors exporter Foo tout simplement.
Davis Herring propose l'exemple suivant :
// module:
export module M;
// This would export A as incomplete:
// export struct A;
struct A {};
export struct A;
// client:
import M;
A a; // OK?
Gabriel Dos Reis pense que cet exemple ne compilera pas car la première occurrence de M.A lui donne module linkage, alors que l'exportation change ce linkage ce qui est illégal. Certains pensent que using ne peut pas changer le linkage d'un nom non plus.
Daveed Vandevoorde ajoute un autre exemple :
// m.cpp
export module M;
export struct S;
struct S {
unsigned n;
};
export S f();
// c.cpp
import M;
unsigned s = sizeof(S); // ??
unsigned sf = sizeof(f()); // ??
unsigned u = S{42}.n; // ??
On estime qu'importer M ne permet pas d'évaluer sizeof(f()) car f() à ce point n'est pas un evaluated context. On convient que export using devrait exporter un nom, quoique même ça n'est pas clair. Faudra déterminer ce qu'on veut savoir ici...
Nathan Sidwell propose cet exemple :
// Foo interface
export module Foo;
namespace Toto {
}
// Bar interface
export module Bar;
void Toto();
À quel Toto le mot Toto se rattache-t-il ici? Gabriel Dos Reis pense que c'est une erreur (modulo le name mangling) car si on mettait les deux dans la même unité de traduction, ça ne passerait pas. Nathan Sidwell estime que c'est plus subtil que cela, dépendant du point d'utilisation, mais qu'il faudrait expliciter le comportement attendu.
Richard Smith se dit d'avis qu'un nom de namespace ne devrait être exporté que si le code client utilise au moins un élément s'y trouvant. Une discussion s'ensuit, pour éclaircir les attentes.
Pour les suites :
On ferme pour dîner vers 12 h 8.
Pause tardive pour dîner. Je parle à ma belle Za, qui est aux prises avec des ennuis de fourmis à la maison et est (c'est compréhensible) un peu découragée; ce genre d'ennui est toujours moins lourd (et encore!) quand on est deux. Seul(e), c'est pire... On essaie de s'entraider à distance malgré tout.
J'apprends par Guy Davidson que Kate Gregory est venue nous saluer, mais je la saluerai une autre fois, ayant un peu les mains pleines. J'ai passé mon dîner à bavarder avec les assurances et avec l'ancien propriétaire (qui est très gentil) pour collecter de l'information et aider un peu, malgré la distance.
J'ai eu une offre pour me présenter chez nos hôtes demain un peu en avance. Herb Sutter et Bjarne Stroustrup seraient là, et on m'a offert de les joindre puisque j'ai écrit un des puzzles à CppCon 2016. J'aimerais bien, mais je suis à pied et c'est un peu loin, alors je vais probablement devoir décliner. On ne peut pas tout faire...
On reprend les travaux vers 13 h 55. Ville Voutilainen nous accueille avec son humour caractéristique, et un peu acide. Le plan est de traiter les trucs les moins controversés cet après-midi, et de garder les trucs plis... croustillants pour ce soir.
La première présentation est faite par Richard Smith et Andrew Sutton. L'idée est de supprimer le mot bool de la définition des concepts, car il est essentiellement redondant. Andrew Sutton rappelle que les concepts ont été construits essentiellement sur le dos de fonctions constexpr, qui devenaient tout juste disponibles à l'époque, puis les variable templates sont apparus et ça nous a semblé être une bonne idée, ce qui nous a donné une deuxième façon de faire.
Andrew Sutton dit qu'on propose ici une seule syntaxe, soit celle des variable templates, sauf que ce ne sera pas un lvalue et on ne pourra pas prendre son adresse.
Daveed Vandevoorde demande si on pourra utiliser un concept dans le contexte où l'on évalue une valeur, par exemple un static_assert, et la réponse est oui. En fait, la terminologie mise de l'avant nous donnera un prvalue booléen.
Le vote est plus bas.
Bjarne Stroustrup dit qu'il cherchait des cas de surcharge, et en a trouvé peu. Il est content que nous proposions une simplification consensuelle du modèle.
Eric Niebler trouve que ce changement améliorera le Ranges TS et en est content.
Gabriel Dos Reis se dit certain qu'on pourra étendre le tout si on voit un besoin réel dans le futur.
Richard Smith s'attaque ensuite à l'équivalence entre deux concepts. Les problèmes notés avec les règles existantes, sur la base de comparaison de séquences de jetons plutôt que sur la base de la sémantique, et débattues à Kona 2017, sont abordés. Dans ses mots, on se basait sur la coïncidence textuelle plutôt que sur la correspondance sémantique, et le résultat était fragile.
Deux approches sont décrites :
Bjarne Stroustrup aime certaines choses dans la proposition, mais n'aime pas que deux écritures comme 1+1 et 2 ne soient pas équivalentes. On discute des plus et des moins avec cette situation. Pour le moment, c'est un cas de Ill-Formed, No Diagnostic Required. On débat de la distinction entre les raisons techniques et les raisons aux yeux des usagers. On rappelle l'exemple du Cowboy::Draw() et de Shapes::Draw() proposé par Herb Sutter dans le passé.
Davis Herring décrit les concepts un peu comme des λ, au sens où chaque clause requires est distinctes des autres.
Andrew Sutton dit que la proposition antérieure favorisait les écritures les plus verbeuses (les plus longues!). Celle-ci ne fait pas le même choix.
Walter E. Brown demande plus d'informations sur l'expérience d'implémentation. Andrew Sutton dit ne pas avoir retouché le tout depuis l'écriture de la proposition. Cependant, il fait remarquer que ça compile plus vite, car les comparaisons à réaliser sont beaucoup plus directes.
Davis Herring demande si ces nouvelles règles ne devrait pas encourager tous les auteurs à utiliser les mêmes concepts de base, et à favoriser les types vocabulaires. Semble que ce soit le cas. Davis Herring recommande que l'on exprime cela clairement dans le texte. Andrew Sutton recommande que l'on conseille aux gens d'utiliser le plus possible les concepts de la bibliothèque standard.
Bjarne Stroustrup pense qu'on peut améliorer certains aspects, mais il aime beaucoup la proposition en général. John Spicer pense que la direction générale est bonne, mais que les irritants restants sont difficiles et ne sont pas spécifiques aux concepts.
Ville Voutilainen recommande que l'on applique cette proposition le plus rapidement possible. Cela accroît la vitesse de compilation et accroît du même coup le consensus.
On vote sur l'ordonnancement partiel sur la base de l'identité des expressions. Unanime.
On vote sur la redéclaration basée sur le caractère identique (ou pas) des jetons, avant desugaring. Consensus.
Les deux s'en vont à CWG, peut-être demain. On progresse!
Hubert Tong présente. Les votes qui précèdent impactent un peu cette proposition, du fait que la situation a changé. Un autre texte, Options for addressing requires-clause syntax ambiguities, accompagne le tout. L'idée est que présentement, il y a des cas de bogues de grammaire agaçants qui rendent certains programmes ambigus. Un exemple est une fonction avec une clause requires, où il n'est pas clair où la clause se termine et où le type de retour de la fonction commence.
Hubert Tong fait la démonstration qu'ajouter systématiquement des parenthèses ne règle pas le problème, car la confusion devient alors associée à la possibilité d'un transtypage du langage C, à moins que les parenthèses ne deviennent obligatoires. C'est ce qu'il propose.
Bjarne Stroustrup demande s'il existe des exemples raisonnables et concrets du problème. Ville Voutilainen souligne que les cas où on n'en voudrait probablement pas sont couverts, p. ex. : requires true.
Quelqu'un mentionne craindre que les usagers qui auront des bogues enverront des parenthèses jusqu'à ce qu'ils disparaissent. Ville Voutilainen dit que ce n'est pas nouveau. John Spicer dit préférer le code homogène, et rendrait les parenthèses obligatoires, mais Hubert Tong trouve que dans certains cas, imposer les parenthèses serait abusif.
Bjarne Stroustrup pense que le problème identifié est assez mineur pour conserver le statu quo. Herb Sutter dit que les gens réagissent négativement à l'exigence de parenthèses. Tom Honnerman dit que passer par les fonctions unifiées règlerait le problème. Chandler Carruth dit ne pas aimer les cas d'utilisation artificiels, mais pense qu'on devrait s'assurer que les usagers ne se trouvent pas devant des messages d'erreur trop cryptiques. Hubert Tong rappelle que la grammaire souffre présentement, et que nous allons payer le prix alors que les concepts se répandent dans le code)
Gabriel Dos Reis demande si c'est un problème d'optimisation. Hubert Tong dit qu'on est plutôt en trait de garder le langage raisonnable.
Jonathan Caves se dit un peu préoccupé. Davis Herring rappelle qu'on fait face aux humains, raisonnables, mais aussi aux programmes auto-générés. Chandler Carruth rappelle que d'autres outils que les compilateurs doivent traiter du code source C++. Herb Sutter suggère qu'on ouvre une Issue et qu'on le traite quand les problèmes surgiront. John Spicer dit que ne pas traiter le problème maintenant nous fait entrer dans un champ de mines; il sera difficile de faire progresser le langage si nous laissons la grammaire dans cet état. David Stone pense que retarder une décision n'est pas sage, surtout si on sait que le problème existe; il fait aussi remarquer que des parenthèses obligatoires, ça s'enlève plus facilement que ça s'ajoute quand le code client existe. Bjarne Stroustrup préfère une solution non-syntaxique, et pense que nous avons le temps de corriger la situation si les problèmes surviennent réellement.
On discute ensuite avec les implémenteurs, qui ne semblent pas craindre que ce soit difficile à implémenter, mais qui craignent pas contre un risque que les modifications ultérieures deviennent plus ardues. Jonathan Caves pense que l'initialisation des bitfields est au moins aussi déplaisante sur le plan grammatical. Herb Sutter demande si CWG doit retravailler la grammaire cette semaine ou si nous pouvons aller de l'avant et ajuster la grammaire ultérieurement; il semble que l'on puisse intégrer les concepts tout de suite.
On prend un vote pour savoir si le changement léger (mais très « haut » dans la liste des règles) de grammaire, qui impose certaines parenthèses seulement et dans un contexte restreint, convient. Consensus.
On prend une pause tardive vers 15 h 41.
Ouf! C'est une grosse journée de travail. Je suis rapidement allé me chercher un café; chanceux, j'ai pu saluer Kate Gregory que j'avais manqué ce midi, et serrer la main à James Widman dont j'ai essayé d'aider une amie à se trouver un emploi en sol canadien ces derniers mois (sans succès, malheureusement, mais elle a trouvé quelque chose en Finlande et semble heureuse).
On reprend vers 16 h 7. Ville Voutilainen nous consulte pour savoir s'il y a de l'espoir d'échapper à une séance de soirée. Il y a de l'intérêt pour y parvenir, mais on verra.
Bjarne Stroustrup présente sa perspective. Il se base sur P0694R0 et P0695R0, et se dit d'avis (a) qu'on a besoin des concepts maintenant, (b) que leur design est déjà bon aujourd'hui, même si on peut encore les améliorer (il fait référence aux travaux de cet après-midi) et que nous devons mieux les utiliser (il fait référence à P0557R0, présenté à Kona 2017).
Les objectifs sont de supporter la programmation générique à la Stepanov, directement dans le code sur le plan conceptuel, et simplifier la programmation générique dans son ensemble. Il veut en fait que la programmation générique soit ordinaire.
Un appel est lancé pour éviter d'attendre la perfection, et éviter de trop restreindre la portée du mécanisme. Il y a selon lui un modèle de base qu'il ne faut pas compromettre. Il supporte les améliorations, et souhaite que des améliorations futures deviennent possibles. Il présente une ouverture à plusieurs avenues intéressantes (concepts locaux, par exemple).
Bjarne Stroustrup propose de focaliser sur la sémantique; les contraintes sémantiques sont à son avis ce qui fait des concepts ce qu'ils sont supposés être. Les problèmes que nous avons tiennent trop souvent au fait que les concepts sont dans notre tête plutôt qu'être écrits.
Les clauses requires sont à ses yeux un peu comme l'assembleur de la programmation générique. Introduire des noms pour décrire les interfaces élève le niveau du débat. Un design sur la base de concepts est préférable à un design sur la base d'interfaces. Bjarne Stroustrup prend pour exemple le goto, général et rapide, mais qui ne dénote pas un niveau d'abstraction suffisant pour nous aider à construire des programmes vraiment riches. Plusieurs autres exemples (macros vs templates, pointeurs de fonctions vs méthodes virtuelles, etc.).
Bjarne Stroustrup recommande une élévation du niveau d'abstraction dans nos réflexions et nos travaux.
Bjarne Stroustrup fait ensuite un rappel historique de la syntaxe, en particulier en lien avec auto et les λ génériques (qu'il aurait préféré voir arriver en même temps que les concepts). Un plaidoyer est fait pour que la syntaxe générale soit adoptée, incluant sort(Sortable&), sur la base de l'argument à l'effet que c'est dans ces termes que les gens pensent. Il explique les diverses syntaxes possibles sur la base de réécritures successives d'une forme à l'autre, et recommande de ne pas briser l'équivalence des diverses écritures, incluant les types de retour des fonctions.
Bjarne Stroustrup suit avec un lien entre concepts et types, et indique que les deux idées sont fortement liées. Un type peut être vu comme un prédicat sur des valeurs, et un concept peut être vu comme un prédicat sur des types.
Une discussion sur la cohérence des bindings s'ensuit, p. ex. : Number f(Number,Number) doit-elle accepter f(3,4.5)? Bjarne Stroustrup présente un examen quantifié de l'application de sa vision à la bibliothèque standard. À cause des paires d'itérateurs, forcer un même binding pour un même concept simplifie le travail dans ce cas, mais la nouvelle bibliothèque standard, à base d'intervalles, devrait être plus légère. Certains algorithmes, p. ex. : std::merge(), ont des requis très complexes, mais qui contiennent de la redondance, ce qui introduit l'intérêt pour les concept type-name introducers.
Des échanges s'ensuivent sur les forces et les faiblesses des différentes formes. Bjarne Stroustrup est d'avis que le consistent binding est une bonne chose, mais que les diverses syntaxes sont toutes utiles.
Avec Consistent Binding | Avec Independent Resolution |
---|---|
|
|
Bjarne Stroustrup présente un plaidoyer pour les concept type-name introduction, par exemple :
Avec Concept Type-Name Introduction |
---|
|
Selon Bjarne Stroustrup, il n'est pas nécessaire de se limiter à une seule notation.
Bjarne Stroustrup fait une intéressante suggestion : la notation T&& sera une rvalue reference si T est un type, et sera une Forwarding Reference si T est un concept. J'aime beaucoup cette proposition.
David Sankel dit avoir expérimenté avec la résolution indépendante et l'avoir trouvé féconde, surtout avec des λ. Bjarne Stroustrup rappelle que les deux options ont du bon, et qu'il a un biais favorable pour la résolution cohérente. Il dit surtout que ce qui est sur la table fonctionne bien en pratique, qu'il existe des voies de contournement pour ce qui accroche un peu, et qu'il pense que c'est prêt.
Chandler Carruth aborde la question du risque de perte d'une capacité de distinction syntaxique. Selon lui, c'est un problème de perception.
David Stone revient sur le cas de std::merge() avec un exemple en trois temps, pour montrer qu'avec un concept intermédiaire Mergeable<In0,In1,Out> ça se lit quand même assez bien, ce qui rend la syntaxe avec concept type-name introduction moins essentielle qu'il n'y paraissait au préalable. Bjarne Stroustrup pense qu'il a une bonne idée, mais son expérience est que les gens tendent à ne pas faire cette étape intermédiaire, et semblent fiers d'avoir écrit beaucoup de code... En fait, devoir écrire un concept pour utiliser la syntaxe avec concept type-name introduction est en soi une sorte de bonus.
Il est 17 h 33 et nous avons encore beaucoup à faire, alors la session de soirée aura lieu.
Je suis allé me chercher des jetons pour le métro en vue des événements mondains de demain, puis je me suis payé le sandwich du jour chez Subway's (mes moyens sont extrêmement limités cette semaine) et je suis retourné travailler. C'est vraiment une très, très grosse semaine.
La salle ce soir est plus petite que celle que nous avons occupé le reste de la journée, et elle est pleine à craquer... tristement, il n'y a que très, très peu de sources de courant dans la salle, et les 60+ personnes ici ont tous un ordinateur portatif. Oh boy...
La séance débute vers 19 h 35.
Tom Honermann propose de supprimer la forme abrégée des concepts. Cette forme est, selon lui, controversée, et il estime que les concepts sont importants au point qu'il soit essentiel d'accroître le consensus. Hubert Tong demande des précisions sur ce qui est retiré, et ce qui pourrait être réintroduit. Tom Honermann explique un peu, mais la salle souhaite entendre l'ensemble de la présentation avant de se prononcer.
Tom Honermann semble préoccupé par la capacité de distinguer un type d'un concept. Il fait une liste d'irritants à ses yeux, et dit prendre le problème sous l'angle de l'entretien du code.
On souligne que dans le cas où le type de retour d'une fonction est déduit du corps de la fonction, par exemple avec une fonction de type auto, on a déjà un cas de variation et de difficulté (relative) similaire dans le langage. Ville Voutilainen demande quels usagers auront besoin de savoir si un paramètre est un type ou un concept. Tom Honermann dit ne pas être certain que ce soit la bonne question. Bjarne Stroustrup demande quelle est l'évidence empirique qui soutient la position décrite par cette proposition. Tom Honermann indique ne pas en avoir une claire car il n'utilise pas vraiment cette syntaxe (il utilise par contre beaucoup les concepts). Une discussion sur la part objective ou subjective d'une position pour ou contre cette syntaxe s'ensuit, je vous passe les détails.
Hubert Tong se dit d'avis que certains cas posent objectivement problème avec cette syntaxe. Il mentionne en particulier le cas du type de retour des fonctions, où l'on pourrait vouloir contraindre une fonction qui aurait, autrement, été auto. Herb Sutter dit apprécier l'effort pour approcher un consensus, et la manière par laquelle le proposeur s'y est pris, mais dit que le consensus ne sera constaté (ou pas) que si un vote est tenu. Dinka Ranns dit que ce qui est frustrant est que la discussion tourne en rond; elle favoriserait la mise au rancart de cette partie des concepts, qui prête à controverse, pour que les concepts soient enfin livrés et utilisés, ce qui faciliterait entre autres la publication du Ranges TS.
Daveed Vandevoorde demande aux gens oeuvrant sur le Ranges TS laquelle des syntaxe ils utilisent. Ce n'est pas la forme abrégée; ils utilisent les deux autres. Eric Niebler dit que la réaction des gens à la forme concise était très négative, donc qu'ils ne l'ont pas utilisée. Il remercie au passage Tom Honermann pour avoir ouvert la porte à un échange ce soir. Bjarne Stroustrup rappelle sa conviction à l'effet que la syntaxe la plus concise facilite l'enseignement des concepts; il pense que supprimer cette syntaxe deviendrait un obstacle à l'enseignement, malgré les bonnes intentions. Eric Niebler dit que dans sa pratique, les concepts de haut niveau (deuxième degré et plus) sont fréquents, et la syntaxe concise ne lui semble pas à propos.
Thomas Köppe dit qu'il lui semble évident que tous ici veulent les concepts, au moins dans la forme complète. Il pense que les versions plus concises peuvent être débattues sans bloquer les concepts dans leur ensemble. Il suggère qu'on adopte les concepts immédiatement, et que le reste soit débattu plus tard, suivant des discussions ciblées. Il estime que les problèmes de fond et de surface sont trop couplés présentement.
Le sujet est chaud, et le ton lève. Heureusement, Ville Voutilainen fait un bon travail, et ferme rapidement la porte aux débordements malgré la taille des égos en situation de conflit. On reprend des échanges plus posés par la suite. John Spicer estime que la tension surgit du fait que d'une part, la syntaxe concise ressemble de près à celle des templates, et d'autre part, on cherche à l'utiliser sans laisser d'indices sur des détails tels que les types assujettis à des contraintes. Sur le plan personnel, j'ai l'impression qu'une partie importante des craintes tient aux habitudes et aux restrictions traditionnellement associées aux templates.
Tom Honermann pense que le passage par une TS est peut-être responsable pour le fait que les débats sérieux sur cette syntaxe aient été, du moins en partie, escamotés.
On échange ensuite sur le meilleur chemin à suivre, soit adopter la forme abrégée tout de suite quitte à la retirer si elle pose problème ou attendre et ne l'intégrer que si un consensus se forme en ce sens. Daveed Vandevoorde dit que des questionnements analogues ont eu lieu dans le passé, par exemple les λ génériques (envisagées pour C++ 11, intégrées avec C++ 14 quand on y a pris goût) ou constexpr (intégré graduellement). Je ne prends pas tout en note car ça tourne un peu en rond, mais les gens s'expriment et ont des opinions proposées.
David Sankel demande si, avec sa proposition, il demeure possible d'utiliser les concepts avec les λ génériques, et Tom Honermann répond que oui.
Le dossier devient politique. Je coupe ici une bonne demi-heure de discussions rudes et lourdes de conséquences. Plusieurs s'expriment, moi y compris.
On en vient à prendre un vote, à savoir incluant les changements apportés plus tôt aujourd'hui (mais pas la proposition débattue explicitement ce soir), inclut-on les concepts dans le WD? Pas de consensus (majorité, mais trop faible).
On prend ensuite un autre vote, à savoir incluant les changements apportés plus tôt aujourd'hui et en retirant la forme abrégée de même que la syntaxe d'introduction de templates (avec des accolades) et les types contraints dans une fonction qui n'est pas un template, inclut-on les concepts dans le WD? On a le consensus pour celle-là.
Je pense que les formes abrégées et autres reviendront lors de prochaines rencontres, mais nous aurons au moins progressé un peu ce soir.
Les discussions se poursuivent un peu pour voir ce qui, dans les diverses préoccupations soulevées, pose le plus problème.
Tony Van Eerd dit avoir une proposition prête pour discussion en vue d'une syntaxe concise, qui ne trouve jamais son chemin jusqu'à une discussion dans EWG, et qu'il aimerait que celle-ci soit abordée cette semaine en vue de déterminer une direction. Plusieurs échangent s'ensuivent à propos de diverses avenues pour le futur. Il y a un malaise dans la salle car certains aimeraient revenir sur des propositions discutées par le passé.
Ville Voutilainen informe les gens présents que des propositions subséquentes à ce qui a été débattu ce soir sont les bienvenues... pour Albuquerque.
On ferme les livres vers 21 h 20. Grosse, grosse journée, et grosse, grosse soirée.
J'étais brûlé après cette journée lourde sous plusieurs aspects. J'ai bavardé avec ma belle Za en marchant vers ma chambre, puis un groupe de collègues m'a rattrapé et m'a invité à aller prendre un verre non-loin de l'hôtel. J'ai donc pris une bière avec John Spicer, Dietmar Kühl, James Widman et Faisal Vali (Dinka Ranns et Daveed Vandevoorde sont allés se reposer), ce qui (je dois l'avouer) a fait du bien. Ce fut bref (le bar fermait tôt, car la toilette des dames avait coulé dans la cuisine... Sérieusement!), mais agréable. Cela dit, de quoi avons-nous parlé? De concepts, de modules et d'IDE (merci à James Widman pour avoir amené un thème différent!).
Cela dit, il reste beaucoup à faire, alors dodo.
Je me suis rasé ce matin, dû à l'occasion modaine qui nous attend ce soir, et
j'ai enfilé jeans, bas et souliers malgré la température (l'été, je suis
essentiellement pieds nus si possible; j'ai toujours chaud) car il y a un code
vestimentaire ce soir, soir « casual, no shorts »
Il fait effectivement chaud ce matin. Heureusement, il y a de la climatisation dans nos locaux, mais elle est légère et on sent la chaleur malgré tout. Ce sera agréable de reprendre les travaux plutôt cérébraux de CWG après les dossiers chauds et très politiques d'hier.
J'ai bavardé un peu avec Barry Hedquist sur mon chemin. Il a manqué l'action d'hier soir, alors je lui ai résumé le tout. On parle d'une personne de grande expérience, alors je n'ai pas eu à lui donner beaucoup de détails pour qu'il comprenne la dynamique.
Nous débutons les travaux vers 8 h 35.
Jens Maurer et Pablo Halpern ont retravaillé le texte pour définir plus formellement l'idée de « une opération est contenue dans une autre ». En effet, normalement, en C++, les opérations d'un même thread ne se chevauchent pas, mais pour ce que ce texte met de l'avant, soit la possibilité d'optimiser l'exécution en utilisant des opérations vectorielles, il faut relaxer cette contrainte. Toutefois, permettre tout chevauchement est un peu trop chaotique aux yeux de la majorité, alors le texte cherche à formuler qu'une itération (conceptuellement) antérieure d'une répétitive ne peut pas être exécutée après une itération (conceptuellement) ultérieure (oui, c'est un risque), bien qu'elles puissent parfois être concurrente et se terminer en même temps.
On essaie d'y arriver avec les termes horizontally-matched et vertically-antecedent, qui représentent en deux dimensions une exécution qui aurait traditionnellement été séquentielle. Les branchements dynamiques (p. ex. : un if) susceptibles de survenir dans une itération mais pas dans l'autre imposent le besoin, au moins occasionnel, de resynchroniser les relations horizontales et verticales. Pour les intéressé(e)s, ce genre de code est un cas patent pour lequel il faut que le compilateur comprenne le sens du code, alors évitez à tout prix l'assembleur inline, les goto et autres formules inconvenantes (il y a une liste dans la proposition) si vous voulez bénéficier de la parallélisation vectorielle.
Ce raffinement nous force à reconsidérer la relation sequenced-before, car les expressions ne sont plus des « moments » dans l'exécution d'un thread. Il faudrait dorénavant dire que A sequenced-before B signifie que la fin de l'exécution de A se complète avant le début de l'exécution de B.
L'autre partie de plaisir tient à ce qui est unsequenced ou indeterminately-sequenced dans le langage, par exemple f0() et f1() dans auto x = f0()+f1(); sont indeterminately-sequenced. Cela dit, si une opération a() précède f0()+f1(), l'intention est que a() demeure vertically-antecedent de f0()+f1().
La terminologie est délicate, car nous voulons couvrir les cas suivants :
+------------A------------+
+----B----+
+----B----+
+------------B------------+
+----B----+
Aaron Ballman souligne que la terminologie proposée utilise coincides-with, qui n'est pas un Term of Art dans le standard, alors on cherche une définition qui dit la même chose mais évite le terme (cela dit, je pense qu'on va devoir retravailler la notion de séquencement dans la description de la machine abstraite pour tenir compte des nouvelles réalités introduites par les calculs vectoriels).
On discute ensuite de ce qui peut être vilain dans une boucle vectorisée, mais Pablo Halpern nous rappelle qu'un compilateur peut toujours refuser de vectoriser ce qui lui semble déraisonnable.
Pablo Halpern pense qu'il y a une chance (faible) de voir ce mécanisme passé au vote samedi, faisant partie (essentielle!) du Parallelism TS, mais il y a des obstacles sur sa route encore.
Gor Nishanov a retouché la formulation de la résolution à Issue 21, incluant une image pour clarifier le propos. L'enjeu est de bien traiter le cas du return_void() dans une coroutine, pour éviter toute ambiguïté. Il ne restait rien de dramatique à faire.
Mike Miller nous informe du plan de la journée. Les modules et les concepts s'annoncent à l'horizon. Évidemment, considérant les travaux d'hier sur les concepts, nous allons traiter un document plus modeste que l'original. Nous devrions aussi examiner la proposition de Herb Sutter sur la génération des opérateurs de comparaison à partir du nouvel opérateur <=>.
On travaille un peu sur la grammaire des énoncés export dans les modules. Le texte se nomme Remove fragment-seq, par Gabriel Dos Reis. On souhaite exprimer que export{a;b;c;} équivaut à export a; export b; export c; et éviter de voir un export apparaître à un endroit inapproprié, par exemple en plein milieu d'une classe. Richard Smith fait aussi remarquer qu'il faut s'assurer qu'un export exporte au moins un élément.
Aaron Ballman souligne que la règle proposée impose un ordre, alors que celle de C ne le fait pas. Richard Smith dit que c'est un choix délibéré, et que la règle pour C++ est un sous-ensemble de celle de C. La raison est que l'ordre d'initialisation dans les constructeurs est important et fait partie du séquencement dans un programme. Aaron Ballman suggère un ajout à l'annexe C du standard, et ceci rencontre l'assentiment général. Jason Merrill dit qu'il existe du code C complexe dépendant de l'ordre écrit d'intialisation, donc l'annexe C sera particulièrement importante.
Il y a des cas obscurs à couvrir, par exemple l'intialisation d'un union. Un exemple particulièrement intéressant est le suivant, qui montre un impact sur la surcharge des fonctions :
struct A { int x, y; };
struct B { int y, x; };
void f(A a, int); // #1
void f(B b, ...); // #2
void g() {
f({.x = 1, .y = 2}, 0); // OK; calls #1
f({.y = 2, .x = 1}, 0); // error; selects #1, initialization of a fails
// due to non-matching member order ([dcl.init.list]
}
Patrice Roy demande si un appel à une fonction pouvant prendre A ou B seulement (sans paramètre subséquent) pourrait mener à une surcharge sur la base du nom des membres et de leur ordre. Richard Smith dit que l'appel serait ambigu. On suggère l'ajout d'un exemple pour l'illustrer.
Hubert Tong propose une formulation pour le type-punning entre deux références, dans un cas de pointer-interconvertibility, par un reinterpret_cast. Ça semble pas mal.
On prend une pause vers 10 h 15.
Petit moment pour aller chercher un café et un croissant, car je n'ai pas encore déjeuné. On discute fort chez CWG sur l'initialisation nommée (Designated Initializers) car les règles pour C++ et les règles pour C diffèrent; cela dit, C++ a des constructeurs, des destructeurs, et opère selon des règles bien différentes dans ces deux moments d'un programme. Il y a de la résistance... On remarque aussi un problème de fond avec la définition des partitions de modules, mais on en parlera en temps et lieu avec les principaux intéressés.
On reprend formellement vers 10 h 44, même si on n'a pas vraiment arrêté pour être honnête.
Mike Miller nous informe que la proposition de Herb Sutter sur la génération des opérateurs de comparaison à partir du nouvel opérateur <=> sera à traiter plus tard, que ce soit à la fin de la semaine ou à Albuquerque.
Richard Smith a retravaillé le texte pendant la pause. L'exemple demandé a été ajouté, et il en va de même pour l'ajout à l'annexe C qui liste des exemples de programmes C qui ne sont pas des programmes C++ légaux.
Hubert Tong demande s'il y a lieu d'expliquer les raisons derrière l'incompatibilité. Richard Smith pense que ce n'est pas nécessaire.
Davis Herring suggère l'ajout d'un exemple combinant des intialisations nommées et d'autres qui ne le sont pas. On procède.
Roger Orr se demande s'il y a de l'espace pour se rapprocher des usages du langage C. Richard Smith parle des initialisations imbriquées, peut-être des initialisations d'éléments de tableau dans certains cas (mais ça se même mal avec les λ). Il y a des subtilités avec les initialisations imbriquées (il faut construire les sous-objets avant de leur accéder; il faut gérer leur destruction...).
On amène ça pour un vote samedi.
Le texte a été retouché par son auteur. C'est un texte complexe qui permet de référer à un tableau de taille connue par une référence de taille inconnue. Il y a des règles compliquées dans le lot, à propos de la propagation des qualifications const par exemple. Richard Smith indique qu'un transtypage affectant les dimensions d'un tableau ne devrait pas affecter sa cv-qualification. L'aire de rien, les cv-qualifications ne sont pas dans les trucs dont on tient traditionnellement compte dans la définition des règles sur les dimensions d'un tableau.
Les interactions entre une fonction prenant en paramètre et à laquelle on passerait une initializer_list sont étudiées.
C'est du beau boulot, mais il reste un peu de travail à faire. On informera l'auteur.
Louis Dionne explique les motivations derrière la démarche. Les changements sont mineurs, d'ordre éditorial. On peut entremêler auto et des paramètres dont les types sont explicités. Jason Merrill fait remarquer que la définition d'une λ générique dans le standard est en un lieu de moins en moins approprié; Roger Orr suggère d'ajouter une référence croisée pour faciliter le repérage.
On se revoit avec des retouches mineures plus tard cette semaine. On souhaite fortement amener cela en plénière samedi, et c'est presque terminé.
Mike Miller nous informe que D0734 a été déposé sur le Wiki. Il s'agit de la nouvelle version du document sur les concepts. Ce bloc ne sera probablement pas terminé cette semaine sur le plan terminologique, mais sera intégré au IS. Le document est important (45 pages), et intègre les différentes recommandations découlant des travaux d'hier. Une note listant les changements accompagne, de même que d'autres messages. Sujet controversé. EWG délègue à CWG certaines réflexions, dans les cas où les discussions chez EWG peuvent manquer de sérénité.
On « ferme » pour dîner vers 11 h 57, mais plusieurs d'entre nous vont lire D0734 sur l'heure du dîner.
Je vais me chercher de quoi manger, et je bavarde un peu avec mon amoureuse Za à propos de la maison, des enfants, de la vie. Il arrive toujours des tas de trucs qui seraient plus simples à gérer ensemble que seuls quand je suis absent... Du côté plus positif, il y a un chic comptoir à salade ici, où la cuisinière assemble sur demande un bol délicieux selon nos désirs. En plus des légumes, des protéines et des noix aujourd'hui, il y avait du bleu (mioum!) et, dans le choix de vinaigrettes, une vinaigrette à l'avocat. Ça fait tout à fait le travail.
Le reste du dîner est passé à lire D0734.
Nous reprenons les travaux vers 13 h 33. Andrew Sutton est parmi nous. Il a apporté des ajustements de dernière minute à D0734 (ça coupe une page sur 45) suivant un malentendu.
Andrew Sutton explique les divers changements appliqués dans le document. Il reste un cas étrange à la lueur des discussions d'hier, vector<auto> v={ ... }; sur lequel on n'a pas voté hier. Un truc comme tuple<auto...> semble donc possible. Mike Miller nous informe que Ville Voutilainen a ouvert un débat à EWG sur f(auto,auto), car il y a divergences de compréhension quant au statut à accorder à cette écriture. Il y a aussi un truc fortement utilisé dans le Ranges TS sur les types des expressions qui est demeuré pour simplifier le tout.
Les travaux incluent une révision linguistique, compréhensible étant donné les délais auxquels Andrew Sutton a été confrontés. Comme c'est souvent le cas chez CWG, on porte une attention particulière au choix des mots.
Jens Maurer trouve un cas amusant où la norme permettrait de déduire un enum avec auto, mais les valeurs d'un enum ne sont pas des types alors on cherche à comprendre l'intention (si ce n'est pas un accident) et à ajouter un exemple, le cas échéant.
La validation d'une clause requires combine un examen syntaxique (les écritures sont-elles bien formées pour les types examinés?) et sémantique. On s'assure que les expression relationnelles et logiques impliquées se comportent dans le respect des attentes.
On attrape au passage quelques erreurs dans la grammaire (un -> manquant dans une spécification de type; un cas où on pouvait mettre const ou volatile mais pas les deux alors que les deux sont tout à fait possibles, ce genre de truc).
Pendant que nous travaillons, nous apprenons qu'EWG a fait le choix de restreindre les cas où auto peut être appliqué, pendant que nous étudions la grammaire associée à ces cas d'utilisation. Eh ben...
Après près de deux heures d'étude de la grammaire et de ses conséquences, Richard Smith fait le constat que dans une fonction retournant un pointeur de fonction, il n'est pas clair où une clause requires pourrait être placée sur le type de retour. En gros :
void ( (*)() ) () ; // il y a deux options; la grammaire proposée s'y prête plus ou moins
// ^ ^
// | |
Il faut faire attention, car nous avons aussi la possibilité de placer le type de retour en fin de signature, et nous ne voulons pas associer la clause requires à cet endroit pour ne pas imposer cette pratique à celles et ceux qui souhaitent profiter des clauses requires en pratique.
On remarque une ambiguïté sur ce qui doit être fait dans une clause requires si aucune substitution ne doit être réalisée (le texte est paradoxal dans sa forme actuelle).
Vers 15 h 25, nous prenons une pause. Étant donné l'événement mondain ce soir, la session de travail se terminera un peu plus tôt qu'à l'habitude, et cela chamboule l'horaire quelque peu.
J'ai pris une petite marche pour aller bavarder avec Bryce Adelstein-Lelbach en lien avec un dossier ligitieux pour CppCon 2017, puis avec JF Bastien pour un truc technique dont nous souhaitions discuter autour d'une bière cette semaine, mais le temps ne semble pas se présenter (nous avons quand même parlé quelques secondes et je vois bien où il veut aller).
Marche, métro, trouver l'endroit, Waterfront.
Verre d'eau, Taureau collectif. Michael Wong et Bjarne Stroustrup surpris
Rencontre, Bjarne Stroustrup No Littering
Petite marche vers la tour du C.N. Trouver l'entrée. Fouille.
Traitement V.I.P.
Famille de Michael Wong. Dame de cirque.
Ascenseur. 104 étages.
En haut, beaucoup de gens. Quatre tables (italien, asiatique, indien, végétarien). Le vin est bon.
Stephen Michell. Famille de Michael Wong. Nos hôtes.
Retour, longue marche. Très, très chaud. Petit peu de temps avec Za. Dodo
Levé trop tard. Douche, départ. Bouchée en chemin. Enfin, journée plus fraîche (ouf!). Toronto un climat plutôt humide cette semaine, mais c'est moins lourd aujourd'hui.
Portes verrouillées. Bavarder aux abords de l'entrée, faute de mieux. Jonathan Caves nous dit qu'il y a huit ans jour pour jour, un vote se tenait pour exclure... les concepts de C++ 0x. On rit un peu.
On finit par entrer à 8 h 30 pile, quand une dame avec les clés arrive. Nos moeurs à CWG impliquent d'arriver beaucoup plus tôt. Ça nous aura fait perdre du temps...
On commence tout de suite.
Hubert Tong présente sa proposition pour réduire les ambiguïtés grammaticales dans les clauses requires, couvrant un irritant examiné lors de la séance de mardi. Thomas Köppe rappelle l'importance d'adapter les exemples dans le document sur les concepts. Jason Merrill fait remarquer que tous les requires true ou requires false ne posent pas de problèmes, car les littéraux sont des primary-expresssion, mais Thomas Köppe dit que requires sizeof(T)==1 et les trucs plus complexes vont demander un peu d'attention.
À titre de clarification, Jens Maurer vérifie que ces ajustements ne touchent que les requires inscrits directement dans les signatures de fonctions, pas dans les concepts nommés, ce que Hubert Tong confirme.
Plusieurs débats grammaticaux s'ensuivent, pour s'assurer que les règles de production sont à la hauteur des attentes. On vise à inclure ces changements grammaticaux directement dans le document principal.
Thomas Köppe dit que la proposition de contraintes sur les λ par Louis Dionne aurait bénéficié du plein support des concepts, mais qu'EWG préfère attendre qu'on ait réfléchi à la question. Il est donc possible qu'un Core Issue soit produit à cet effet.
Le déplacement de la définition des λ génériques vers une autre section a été fait. Louis Dionne explique sa démarche. Il fallait laisser une trace du déplacement, pour faciliter le repérage, ce qui a été fait dans une note.
À la fin de [expr.prim.lambda], un paragraphe est introduit pour définir ce qu'est une λ générique. On l'ajuste un peu pour que le début du paragraphe dise ce qu'il définit, et on retravaille l'exemple pour qu'il soit plus « parlant ». Faisal Vali fait remarquer que la définition proposée est incorrecte, reposant sur la présence du mot auto dans ses paramètres, et appuie sa conception sur l'exemple suivant :
[](auto (*p)()->char){}
On amène ça pour fins de vote samedi.
Gabriel Dos Reis présente une adaptation de la grammaire des modules pour la simplifier. Roger Orr repère un cas suspect que la nouvelle grammaire permet; Gabriel Dos Reis est d'accord et fait l'ajustement sur-le-champ. Dinka Ranns fait remarquer un autre endroit dans le document sur les modules qui nécessite des ajustements (un passage erronné, et une référence à la partie de la grammaire qui a été élaguée).
Je n'ai pas pris beaucoup de notes car les travaux grammaticaux se racontent mal, mais il y a environ une demi-heure de travail ici.
On veut adopter le tout, mais il faudra voir la version de la TS sur les modules avec changements intégrés d'abord.
Nathan Sidwell présente le document. Il est identifié par un P, alors on le change pour un D.
Les changements à apporter sur ce document sont mineurs, mais nous faisons le constat que certains passages du TS sur les modules mériteraient d'être consolidés et restructurés pour que les définitions soient plus claires, et pour qu'elles apparaissent avant qu'elles ne soient utilisées.
Dinka Ranns fait remarquer que le requis sur l'unicité du module interface unit d'un module donné n'est pas exprimé assez clairement pour indiquer l'intention. On retravaille. On discute ensuite de l'interaction entre le langage et les outils, car il faut (pour toutes fins pratiques) que le fichier d'interface soit identifié, que ce soit pas une option de compilation ou par un suffixe particulier. Cela dit, il faut l'exprimer correctement.
On regarde rapidement les changements faits dans ce document. C'est pas mal.
Pause vers 10 h 17.
Je vais rapidement me chercher un café et un muffin, je croise des collègues discutant de politique assez lourde de conséquences (vous ne verrez pas tout dans ce document, mais c'est un peu normal et j'espère que vous comprendrez), et je reviens chez CWG pour la suite des travaux.
On reprend vers 10 h 39.
Richard Smith est parmi nous. On discute du problème des tableaux de dimension inconnue et de la propagation des cv-qualifiers. Il propose un exemple pervers qui permettrait, autrement, de contourner le système de types :
int t[3];
int (*n)[5];
int (**b)[] = &n;
*b = &t; // violated the type rules (changes what n points to... evil, evil stuff)
(*n)[4] = 1; // access no-existing array element --> off-by-one error; UB
Il se trouve que les débordements de tableaux tombent dans les mêmes clauses du standard que les conversions de cv-qualifications. Oh boy...
Jens Maurer suggère par la suite que la procédure pour examen terminologique des TS par CWG soit clarifiée. La profondeur de l'analyse à faire avant de réaliser une fusion dans un IS n'est pas la même en fonction de l'étape où nous en sommes dans le processus. Roger Orr suggère pour sa part qu'on demande une proposition formelle dans chaque cas.
On revient sur les concepts.
Andrew Sutton présente les changements les plus récents. On reprend là où les travaux se sont interrompus hier (les template template arguments); notez que j'ai manqué la dernière heure-et-demie de ces travaux.
Un exemple irritant, mais avec lequel il faudra vivre quelques temps, est S<T>::h() dans :
template<typename T> concept C = true;
template<typename T> concept D = true;
template<C T> struct S {
void f();
void g();
void h();
template<D U> struct Inner;
};
template<C A>
void S<A>::f() { } // OK: template-heads match
template<typename T>
void S<T>::g() { } // error: no matching declaration for S<T>
template<typename T> requires C<T> // error (no diagnostic required): template-heads are
void S<T>::h() { } // functionally equivalent but not equivalent
template<C X> template<D Y> struct S<X>::Inner { }; // OK
L'idée est qu'on a un cas d'équivalent, mais pas functionally equivalent. On convient qu'on va probablement trouver une forme canonique et rendre les deux pleinement équivalents éventuellement, mais pas cette semaine.
L'amitié, mêlée aux
templates et aux
concepts,
mène à des règles divertissantes et à des jeux de mots amusants. On se
retrouve entre autres à générer un ensemble infini d'amis prospectifs, puis à
choisir un « meilleur ami »
Jens Maurer trouve un cas intéressant où il pourrait y avoir un nombre atypique de surcharges pour une même fonction friend. On a quelques discussions sur une espèce de bogue conceptuel avec un passage et la compréhension de l'intention qui s'en dégage (Hubert Tong parle d'une note « horriblement utile »). On pense rendre les amies non type-dependent avec requires ill-formed à court terme, le temps de trouver une résolution pour les réintégrer plus tard, ou simplement d'enlever l'exemple sans trop en parler pour le moment. Ce sera ça pour le moment.
On corrige quelques exemples qui contiennent des fautes mineures. C'est extrêmement abstrait, les concepts, alors c'est presque inévitable.
On arrête à midi.
Petit tour au bar à salade du bâtiment, puis retour au boulot. Je bavarde avec Roger Orr de la vie et des particularités de la gestion de BSI, l'équivalent britannique du Conseil canadien des normes, dont il est le représentant officiel. Par la suite, je me dirige vers la salle où se rencontrera SG12, en conjonction avec Stephen Michell qui dirige WG23 dont je fais aussi partie. Quelques personnes sont déjà là, mais c'est une petite salle. Je rencontre les enfants de Hal Finkel, qui sont adorables et ont des toutous en forme de maladies.
La salle se remplit doucement, et nous sommes plus d'une dizaine, dont plusieurs « gros noms ».
Les travaux commencent vers 13 h 40. La salle est drôlement organisée, et la mise en place d'un projecteur prend plus de temps que prévu.
Michael Wong fait l'introduction du changement philosophique qui sous-tend le nouveau mandat de SG12. Il voit l'arrivée de la GSL comme un bon point de départ pour trouver une jonction entre WG23 et SG12. Ses travaux dans le monde des systèmes hétérogènes et des véhicules autonomes ont fait en sorte qu'il soit approché par OpenCL pour y présider les travaux en lien avec la sécurité, et a approché Gabriel Dos Reis pour assurer le lien du côté de C++.
Michael Wong rappelle que quand des groupes hors-WG21 cherchent à définir les règles pour C++, les résultats tendent à ne pas bien s'harmoniser avec notre langage. Il dit avoir espoir qu'un effort provenant « de l'interne » sera plus fécond.
Stephen Michell présente tout d'abord WG23 sur le plan historique et sur le plan des pratiques, à partir du cas d'Ada qu'il connaît bien. Le premier rapport de WG23 remonte à 2010, le deuxième en 2015, et ils travaillent sur le troisième. Ils ont des annexes par langage, et en couvrent quelques-uns (Ada, C, Fortran, Python, etc.). Ils espèrent pouvoir ajouter une annexe pour C++, et sont conscients que C++ est utilisé concrètement dans des situations où la sécurité compte.
Stephen Michell parle un peu d'Ada, qui a la réputation d'être sécuritaire bien que l'annexe contienne un catalogue de plus de 50 vulnérabilités connues. Les blocs à risque sont typiquement marqués unchecked. Hal Finkel demande comment les blocs qui ne sont pas unchecked réagissent lors d'un comportement à risque; Stephen Michell parle de levée d'exceptions.
On échange un peu sur le langage Spark. Gabriel Dos Reis veut savoir où c'est utilisé; Stephen Michell parle de Toyota, où ils ont vécu une forme d'enfer sur terre ces dernières années en lien avec leurs pratiques discutables de développement logiciel.
Stephen Michell explique le découpage de leur document en clauses, et parle en particulier de la section qui offre des recommandations de correctifs.
Stephen Michell fait remarquer que certaines organisations filtrent les langages et éliminent des parties qu'elles jugent « peu sécuritaires », mais que WG23 en soit ne recommande pas de tels sous-ensembles. Patrice Roy fait remarquer que le standard de C++ tient à jour une annexe listant avec précision les divergences entre C++ et C; Stephen Michell dit qu'on pourrait l'enrichir pour tenir compte plus en détail des vulnérabilités.
Bjarne Stroustrup dénote une partie de la démarche de WG23 qui, à ses yeux, complique le travail des gens utilisant leurs documents. Il pense qu'un guide de bonnes pratiques est associé de près au langage qu'il couvre. Les règles de MISRA ou de JSF font cela, selon lui : elles sont spécifiques au domaine. Par exemple, pour un avion de chasse, Bjarne Stroustrup dit que la règle est simple. Essentiellement, ça dit : « don't use new after the plane takes off » plutôt que de chercher à couvrir des tas de petits cas ici et là. Bjarne Stroustrup explique ensuite comment la GSL aborde le problème.
Bjarne Stroustrup indique que la GSL ne couvre pas encore des champs d'application spécialisés tels que le temps réel strict, mais pense que c'est une question de temps. Il explique aussi l'importance de ne pas attaquet le langage en entier d'un coup, car le problème est trop vaste.
Bjarne Stroustrup explique comment les règles s'intègrent au langage et sont pensées pour être mise en application à travers des outils. Les règles peuvent être brisées de manière contrôlée, mais nous cherchons à les placer derrière une interface pour éviter qu'elles ne polluent le code dans son ensemble. La GSL est un effort collectif; Bjarne Stroustrup donne un aperçu de l'étendue et de la diversité du groupe de contributeurs.
Stephen Michell dit dit que le rapport réfère à JSF++ mais que ça a quinze ans; Bjarne Stroustrup se dit ravi, mais explique que l'on a beaucoup progressé depuis. Le document de CERT est pas mal, mais se situe à un autre niveau.
Gabriel Dos Reis demande quels sont les critères et les processus par lesquels WG23 identifie les vulnérabilités. Stephen Michell dit qu'ils opèrent sur la base de vulnérabilités rapportées sur le terrain, mais c'est un peu « bas niveau » en pratique.
Hal Finkel parl parle de ce par quoi on peut exploiter le comportement indéfini en C++ pour rendre les systèmes plus robustes, en instrumentant le code de manière à réagir dynamiquement aux circonstances. Le problème est de faciliter la réaction à des bris des présomptions qui sous-tendent ces instrumentations.
Bjarne Stroustrup indique qu'en C++, un pointeur brut n'est jamais responsable du pointé. Nous sommes capables maintenant d'assurer de manière statique le suivi de la responsabilité sur un pointé.
Michael Wong rappelle les travaux en cours sur les contrats.
Gabriel Dos Reis demande à Michael Wong quel est l'objectif poursuivi; Michael Wong dit dit qu'il aimerait qu'on parvienne à qualifier C++ de ISO 26262-Safe, donc qu'on puisse l'utiliser dans l'industrie automobile, en particulier pour le fonctionnement de voitures intelligentes.
Bjarne Stroustrup ne pense pas qu'on puisse qualifier le langage en entier pour une telle qualification, mais envisage une combinaison de langage, outils et règles.
Michael Wong parle d'un cas récemment rencontré où un Pacemaker est devenu irrégulier suite au téléchargement de mise à jour. La solution fut d'avoir un plan B, ou Fallback. Michael Wong pens pense que MISRA est hors de question pour la programmation contemporaine; les facilités existantes pour la programmation aujourd'hui sont tellement plus vastes et plus puissantes qu'elles ne l'étaient à l'époque... Bjarne Stroustrup dit que MISRA recommande de programmer sans un sous-ensemble... de C, pas de C++.
Bjarne Stroustrup dit que la GSL est née d'un effort pour répondre à la question : « qu'est-ce que le C++ moderne? ».
Hal Finkel demande quels sont les irritants qui empêchent C++ d'avoir une certification telle que ISO 26262.
Bjarne Stroustrup dit que le standard explique ce qui peut se faire avec le langage. C'est un document bon et nécessaire. Il y a bien sûr un besoin pour des guides de saines pratiques, mais ces guides sont des documents d'un autre ordre.
On examine un peu le document de WG23. Hal Finkel suggère de regarder Dead Code Elimination. Melissa Mears fait remarquer que le document laisse de la place à des applications de pratiques qui sont généralement peu recommandables (donc qu'il n'est pas absolutiste). Gabriel Dos Reis constat constate que le document n'impose pas nécessairement des tests dynamiques, une bonne chose. Bjarne Stroustrup remarque que les templates sont merveilleux pour éliminer le Dead Code.
Lisa Lippincott prend le plancher. Elle trouve que les travaux sur les contrats bloquent en partie sur la base d'une mauvaise compréhension des assertions, et cherche à préciser de manière abstraite ce qu'elles font, sur la base de principes fondamentaux. Elle a pour objectif de faire des assertions un mécanisme universel et répandu, partout.
Selon Lisa Lippincott, une assertion permet d'identifier le comportement incorrect dans un certain contexte, laissant le comportement correct intact. Une assertion, même activée, ne devrait pas modifier le comportement du contexte avoisinant. L'échec d'une assertion peut prendre plusieurs formes, et ne se limite pas à retourner faux ou à terminer un programme. Certains échecs peuvent être diagnostiqués, d'autres ne le peuvent pas. Elle inclut une levée d'exception si celle-ci quitte le contexte immédiat.
Selon Lisa Lippincott, certains besoins gouvernent le recours aux assertions. Elle propose une liste d'une dizaine de cas, grosso modo. En particulier, il y a un aspect conservateur aux assertions, du fait qu'on peut (modulo les effets de bord) les insérer dans un programme existant sans le briser.
Lisa Lippincott passe ensuite à la machine abstraite (amusant, considérant mes travaux récents sur le sujet). Elle met en relief les aspects indéterministes, non-spécifiés ou indéfinis du langage. C'est ce qu'elle cherche à adresser avec les assertions.
Lisa Lippincott présente la fonction suivante :
bool unspecified() noexcept;
Cette fonction « magique » serait telle que le compilateur peut insérer du code qui retournera true ou false selon des circonstances qui lui appartiennent. Elle ajoute la fonction suivante :
void undefined_behavior();
Celle-ci peut être implémentée en écrivant une fonction [[noreturn]] contenant un return. Enfin, elle présente des cas de implementation-defined, où les paramètres sont sous le contrôle des usagers. Elle décrit ces fonction comme les paramètres de la machine abstraite. J'aime beaucoup son approche. Sa proposition donne beaucoup à réfléchir (c'est Lisa Lippincott après tout!), mais en gros elle modélise la machine abstraite comme une machine paramétrée par des fonctions auxquelles le code client n'a pas accès. Sur la base de ces fonctions spéciales, elle parvient à paramétrer le comportement d'une assertion de manière à clarifier les attentes.
Gabriel Dos Reis demande des précisions sur les impacts de la démarche. Lisa Lippincott présente un pseudocode (presque du C++ valide) décrivant ce qu'elle conçoit comme le comportement attendu lors d'une exception. On trace des liens avec ce que l'on attend d'un contrat.
Gabriel Dos Reis rappelle la génèse de SG12, qui tient à :
if(!p) {
// ...
}
assert(p != 0); // ceci peut affecter le code plus haut!
On aurait, dans le modèle préconisé par Lisa Lippincott, des fonctions constexpr paramétrées par unité de traduction et par classe d'assertion, pour déterminer un comportement lorsqu'une assertion est rencontrée. Elle présente les forces et les faiblesses de chacune des trois approches qu'elle avait envisagées.
On prend une pause vers 15 h 30.
Nous sommes au quatrième étage. Je descends au deuxième prendre un café; je croise un collègue qui a remarqué qu'il existe une conversion de unique_ptr<T[]> vers unique_ptr<T*>, qu'il existe une conversion de unique_ptr<T*> vers shared_ptr<T*>, mais qu'il n'existe pas de conversion de unique_ptr<T[]> vers shared_ptr<T*>. Il se demande ce qui doit être fait pour corrriger la situation (ça vaut la peine, car il y a un effort de préservation du custom deleter sous la couverture qui n'est pas à la portée de tout le monde) alors je le guide vers LWG.
Je croise aussi JF Bastien, avec qui j'ai discuté à quelques reprises cette semaine pour essayer de régler un truc qui m'agace beaucoup à bas niveau dans le langage. On manque un peu de temps pour parler cette semaine (on travaille tout le temps), mais il va manger dans un pub non-loin tantôt alors si on ne termine pas trop tard chez SG12, j'irai avec eux.
On reprend vers 15 h 55.
Lisa Lippincott poursuit. Elle montre les avantages et les inconvénients des diverses applications de sa démarche. Aaron Ballman soulève la question du caractère apparemment non-statique de la fonction unspecified(), mais Lisa Lippincott indique que cette fonction peut être constexpr mais locale à chaque unité de traduction. Elle présente trois manières de configurer les classes d'assertion; dans l'un des trois cas, la fonction unspecified() repose sur le comportement d'un oracle prédisant que l'assertion échouera ou pas. Trois autres cas, plus nichés, suivent et couvrent ce qui pourrait s'appliquer dans le cas des systèmes embarqués ou des programmeuses et des programmeurs débutants.
Lisa Lippincott dit préférer qu'on évite d'avoir recours aux assertions en tant que mécanisme de contrôle du flot de contrôle d'un programme.
Selon elle, une fonction de très bas niveau comme prevent_continuation() pourrait être utilisée pour construire les abstractions primitives qui sous-tendent les assertions. Stephen Michell fait remarquer qu'il ne voit pas de mécanisme de récupération dans la présentation, mais Lisa Lippincott dit qu'on a escamoté cette diapositive (elle propose un prevent_continuation_handler() pour donner un levier de récupération de dernière minute aux programmes).
Aaron Ballman met en garde contre les cas de récursion infinie lorsque le système est si mal en point que tenter de récupérer provoque une autre tentative de prévenir la poursuite du programme. On examine quelques options.
Gabriel Dos Reis dit que cette présentation le convainc de l'importance d'avoir fait des contrats une partie de l'interface (des fonctions). Lisa Lippincott est du même avis.
Gabriel Dos Reis demande à Stephen Michell s'il estime qu'il y a un espace de travail conjoint entre WG21 et WG23 sur la base de ce qu'il a entendu aujourd'hui. On parle de tenir des rencontres communes pour ces deux groupes en un même lieu pour faciliter les prises de contact et la collaboration. WG23 est un relativement petit groupe en comparaison avec WG21, et il est possible d'accommoder quelques individus de plus pour un groupe de l'envergure de WG21.
Michael Wong met en valeur l'intérêt d'avoir placé la sécurité sous l'ombrelle de SG12, ce qui donne un contact direct entre les deux groupes. Bjarne Stroustrup suggère de faire des références croisées bidirectionnelles entre la GSL et l'annexe C++ du document de WG23.
On échange ensuite sur les suites à donner à la présentation de Lisa Lippincott. Elle nous explique qu'elle présentera le tout devant EWG demain après-midi. JDG n'est pas certain que les contrats en bénéficieront directement. Lisa Lippincott dit qu'une possibilité serait de voir les contrats comme une paire comprenant la syntaxe pour placer des assertions dans un programme et la spécification du comportement attendu. On échange brièvement sur assert_always dans les contrats, qui semble être perçu comme un mécanisme de contrôle du flot d'exécution par certains (il y a de la dissension sur le sujet).
Gabriel Dos Reis s'intéresse à la propagation des assertions émises par un contrat, et à l'acquisition de connaissances qui peut en résulter. Selon lui, ceci pourrait permettre à un optimiseur d'apprendre sur un programme et de générer du meilleur code. On discute un peu de la granularité des assertions.
Gabriel Dos Reis décrit décrit le problème, soit démarrer la vie d'un objet à partir d'un memcpy() dans une variable non-initialisée. Évidemment, il faut éviter d'utiliser comme destination tout objet ayant un destructeur non-trivial. La proposition ne couvre que des objets de même taille.
La question de la fin de la vie de l'objet et de son redémarrage est discutée.On est heureux avec cela. Ça va être présenté à EWG, probablement à Albuquerque.
La discussion qui suit porte sur les manières de collaborer de manière constructive avec WG23, et sur l'ajustement au mandat de SG12.
Une fois les échanges terminés, je marche vers SG1 pour aller à la
rencontre de JF Bastien. Sur le chemin, je bavarde un peu avec
Pablo Halpern
et Aaron Ballman sur la possibilité d'utiliser std::launder()
pour débuter la
vie d'un bloc de bits pour le considérer d'un type donné. Je ne suis pas
convaincu que std::launder()
soit la bonne fonction ici. Truc amusant : Pablo Halpern a pensé au mot bless()
pour un tel mécanisme, qu'il utiliserait pour
implémenter un destructive move lors de la réallocation du substrat d'un
conteneur tel qu'un vecteur; c'est le même nom que j'avais envisagé, mais la
connotation religieuse me fait penser que c'est un mauvais choix (c'est bon
pour Perl, mais
Larry Wall ne cache pas ses convictions religieuses
Pour un groupe de l'envergure et de la diversité du nôtre, mieux vaut trouver
autre chose).
J'ai écouté, sans participer, les dernières minutes des travaux de SG1.
Resto (Sin & Redemption). Bonne bière, salade de roquette et de chèvre. Jasette sur bit_cast et memcpy().
Retour à la séance de soirée sur la réflexivité. Je suis secrétaire.
Nous débutons les travaux à 19 h 37. Quatre propositions sont à l'horaire et le temps est compté. Je ne laisserai ici qu'un bref résumé, du fait que les notes exhaustives que j'ai prises pour le comité ne sont pas destinées à être distribuées à l'extérieur. Les grandes lignes :
Nous devions examiner quatre propositions en deux heures. Les probabilités que ça fonctionne étaient ... minces
Nous avons pris quelques votes, principalement des encouragements et des conseils pour les auteurs des propositions
Retour à l'hôtel, bref bavardage avec Za. Je produis une version anglaise d'un document décrivant une offre de formation que je suis susceptible de donner à Shangaï en 2018.
Dodo vers 1 h.
bla
On commence vers 8 h 35.
Jason Merrill présente un autre cas particulier pour le traitement des « initialisations uniformes », soit :
tuple t{tuple{1, 2}}; // Deduces tuple<int, int>
vector v{vector{1, 2}}; // Deduces vector<vector<int>>
... car EWG a statué que ceci :
vector v{vector{1, 2, 3}};
... devrait appeler vector<int>. Eh ben... Avec le traitement spécial de trucs comme auto x{1};, depuis C++ 17, on commence à accumuler les alternatives dans le code des compilateurs.
La formulation proposée semble convenir à tous. On amène ça en plénière samedi.
On examine l'intégration des changements débattus ces derniers jours au document dans son ensemble.
Nathan Sidwell se questionne sur la pertinence de la production grammaticale module-export-declaration, qui provoque présentement une ambiguïté grammaticale. On retouche cette section de la grammaire. Entre autres choses, on rapproche aussi l'exemple du mot clé export du texte qui l'explique.
Aaron Ballman suggère de clarifier ce à quoi s'appliquent les annotations appliquées à une déclaration de module.
Gabriel Dos Reis va faire des correctifs. On passe à un autre document sur les modules, soit celui de Nathan Sidwell. Les deux seront fusionnés plus tard aujourd'hui si tout se passe bien.
Nathan Sidwell propose une manière de clarifier le rôle du mot clé export, de même que la grammaire qui l'accompagne.
Patrice Roy fait remarquer une incohérence sur le fait qu'un passage dit qu'un module a exactement une interface, alors qu'un peu plus pas on indique que le module global n'a pas d'interface. On retravaille un peu cette section. Richard Smith souligne que le module global comporte quelques cas d'exceptions, ce qui invite une déclaration d'ordre général quant à ce qui le rend particulier, et à sa définition un peu plus hâtive (pour éviter les références de type see below). On travaille un certain temps là-dessus. On finit par distinguer formellement named module et global module, ça simplifie les choses.
Le problème est intéressant, et survient en particulier avec les tuple. Soit :
struct MyType {
MyType(MyType&); // no 'const'
};
... il se trouve qu'insérer un tel type dans un autre possédant un constructeur de copie par défaut (=default, vraiment) enpêche d'instancier le type en question, qu'on cherche à le copier ou non :
template <typename T>
struct Wrapper {
Wrapper(const Wrapper&) = default;
T t;
};
Wrapper<MyType> var; // fails to instantiate
Botond Ballo vient expliquer la situation. Il propose que la classe demeure utilisable même si elle n'est pas copiable.
Richard Smith fait remarquer que nous avons de la terminologie connexe ailleurs dans le standard, qui pourrait servir à titre d'inspiration.
Jens Maurer fait remarquer que la résolution n'indique pas où changer le texte. On corrigera la situation. Mike Miller propose une reformulation pour alléger la lecture.
Richard Smith signale que le paragraphe 2 a été modifié, mais que le paragraphe 3 doit l'être aussi; ce dernier touche aux spécifications d'exceptions, et influence les signatures.
On se demande jusqu'où on ira avec cette proposition cette semaine. L'assentiment général semble être à l'effet que ce sera traité à Albuquerque.
C'est un dossier qui demande une lecture attentive, pour éviter de provoquer des const_cast accidentels.
On pause vers 10 h 15.
Pause rapide, on prépare la rencontre de la délégation canadienne ce midi. Au retour à CWG, je bavarde avec un nouveau participant qui, il s'avère, a vécu à Montréal une vingtaine d'années et a étudié à la Polytechnique, bien qu'il vienne de Calgary. Très chic type, mais extrêmement allergique aux arachides, alors quand l'un d'entre nous est arrivé avec du beurre d'arachides, nous avons assuré un périmètre de sécurité entre eux.
On reprend vers 10 h 41. Le plan de match est de finir de couvrir les modules, puis de passer l'essentiel du reste de la journée sur les concepts.
Faisal Vali fait remarquer que nous n'avons toujours pas d'exemple d'un proclaimed-ownership-declaration. On parle ici d'un module qui exporterait une partie de l'interface d'un autre module comme s'il s'agissait de la sienne.
Jason Merrill remarque que l'un des exemples mentionne des noms de fichiers dans les commentaires, une chose que nous évitons. On reformule.
Richard Smith remarque qu'un passage malheureux donnerait à la plupart des noms dans un programme C++ un module linkage. On resserre un peu la formulation.
Un autre passage semble faire du domaine d'un module quelque chose de beaucoup plus vaste que ce qui était prévu. Ici encore, on resserre la formulation.
On fait des retouches mineurs (fautes d'orthographe mineures, fautes d'accord, virgules). On va l'amener pour vote samedi à titre de PDTS.
Hubert Tong suggère de remplacer « concept » par un synonyme dans les cas où on ne réfère pas à l'acception technique du terme.
Andrew Sutton indique que la plupart des changements étaient mineurs. Le plus gros changement était de décrire les contraintes selon les nouvelles modalités, ce qui se nomme désormais cumulative-constraints-expression.
Hubert Tong discute de l'intérêt
d'une note non-normative pour clarifier la relation entre les clauses
requires et l'édition des liens. Dans ses mots : « signature does
not contain the content of the requires-clause really; if you want them to
link, don't use a requires-clause (because they're different functions when in
different translation units) »
.
La position dans la grammaire des clauses requires est agaçante car, pour le moment, elles pourraient s'appliquer à des int, ou à la dernière déclaration d'une séquence de déclarations séparées par des virgules.
Richard Smith a remplacé cumulative-constraints-expression par quelque chose d'un peu plus harmonieux.
Pour les clauses requires, Richard Smith pense que deux templates identiques dans deux unités de traduction distinctes sont une seule et même entité si les clauses requires concordent; par contre, Hubert Tong souligne que le problème demeure entier avec les λ.
Jens Maurer signale que la satisfaction d'un concept peut varier selon le point où il est déclaré dans un fichier, de par l'apparition de nouvelles déclarations dans le texte du programme.
Certaines questions profondes demeurent; on pense pouvoir les aborder en tant que Core Issues et ne pas ralentir l'intégration de ce document au IS. On a un cas de sémantique brisée, rapporté par Hubert Tong, que nous allons chercher à corriger tantôt.
On ferme pour dîner vers midi.
La délégation canadienne se rencontre au Sin & Absolution, à la suggestion de JF Bastien.
Je reviens chez CWG à 14 h.
Les travaux se poursuivent, mais les circonstances font que j'ai manqué le début des débats. On travaille for sur les clauses atomiques de 17.10.1.2.
L'évaluation des substitions peut échouer en soi, et peut échouer pour plusieurs autres raisons (noexcept par exemple; requires pourrait intervenir là). À quel point devrait-on intervenir dans la terminologie des concepts en soi pour réagir à un problème, si une partie du travail est faite ailleurs?
Je ne tiens pas les détails à jour ici, mais il y a une heure de travail... On frappe un cas où plusieurs niveaux imbriqués de requires sont requis, par exemple :
f(T t) requires {
std::tuple_size<T>;
requires std::tuple_size<T> == 2; // ceci serait suffisant, normalement
} {
}
Patrice Roy argumente pour le second cas, qui subsume le premier à ses yeux (utiliser std::tuple_size<T> repose sur son existence). Il y a des frissons, mais pas d'opposition formelle.
Hubert Tong demande ce qui se produit si un static_assert échoue dans une clause requires; Andrew Sutton rappelle que ces instructions ne peuvent apparaître dans une clause requires.
Hubert Tong constate qu'un concept qui n'est pas value-dependent peut être évalué au point d'instanciation. On rit, mais on trouve une solution.
Aaron Ballman identifie un cas très non-normatif où on trouve un exemple... dans une note en bas de page!
Plusieurs trucs profonds. Je vous passe les détails. On pause vers 15 h 30.
Brève pause. Tout le monde est fatigué, et la plénière (traditionnellement le vendredi après-midi) ne viendra que demain (samedi). Un biscuit, une demi-tasse de café, quelques bons mots pour des collègues (qui le méritent bien; quelle immense semaine!), et on se remet au boulot.
Plusieurs d'entre nous ont vécu la même expérience hier : essayer de lire un livre ou un article dans un magazine, se trouver à re-lire plusieurs fois la même phrase, et s'apercevoir qu'on a perdu connaissance plusieurs heures plus tard.
Je m'apprêtais à travailler sur les concepts avec CWG, mais j'ai reçu un courriel par Hans Boehm me demandant de venir défendre P0484R1 chez SG1.
Sur le chemin, j'ai croisé Faisal Vali qui souhaitait voir les notes de la rencontre sur la réflexivité d'hier soir. En attendant de passer chez SG1, j'ai fait une mise à jour du Wiki de SG7. J'espère que ça rendra service.
J'ai profité du fait que Torvald Riegel présentait quelque chose sur les façons de faire de SG1 pour appeler mes assurances collectives et clarifier un imbroglio en lien avec une de mes filles, Calypso, qui est aux études (donc couverte par mes assurances) mais qui n'avait pas été remboursée lors d'un achat de médicament cette semaine.
ma présentation
Billy Baker
Sushi. Za
Dodo. Épuisement
bla
bla
paul preney
plénière
ff
CWG de 11 h 55 à 13 h. On va faire un peu de classement des Issues.
Que penser de ceci :
template<typename T, int N> void g(T (* const (&)[N])(T)) { }
int f1(int);
int f4(int);
char f4(char);
void f() {
g({ &f1, &f4 }); // OK, T deduced to int, N deduced to 2?
}
On n'a pas clarifié ce qui devrait être fait ici : est-ce déductible, ou est-ce ambigu? On prend un vote rapide, et la majorité est d'avis que ça devrait être bien formé. Davis Herring pense que le texte est correct (mais qu'il pourrait être amélioré), et que les implémentations sont en faute. Jens Maurer va retravailler le passage.
Richard Smith fait remarquer un truc amusant :
struct A { A(); } a;
A a1 = {a}, a2 = {{a}}, a3 = {{{a}}}; // a1 Ok, a2 Ok, a3... brisé
Ça paraît mal de prime abord. Ça arrive quand on initialise un objet ou un conteneur à plusieurs niveaux. Selon Richard Smith, il faudrait permettre deux niveaux d'accolades pour lever certaines ambiguïtés. Daveed Vandevoorde suggère que a1 soit malformé, mais Richard Smith dit que ça devrait rester correct pour des raisons historiques. On convient a2 devrait être incorrect, et on nomme Jason Merrill in absentia pour s'en occuper.
Richard Smith s'est aperçu que ceci est incorrect avec un if constexpr, mais correct avec un if :
template<void *P> void f() {
if constexpr (P) {} // ill-formed, can't convert 'void*' to 'bool' in contextually converted constant expression
}
Il y a dissension sur le traitement de ce cas. Richard Smith fait remarquer que ce genre de manoeuvre est commun dans Boost par exemple. Hubert Tong ajoute que ça survient aussi quand on mélange des bibliothèques de diverses sources.
John Spicer pense qu'il va falloir changer les règles, mais faudra probablement que ça passe par EWG.
Richard Smith souligne ce qui suit :
struct A {};
struct B : A {};
using T = const B;
A a = true ? A() : T();
Ici, l'expression est malformée : pas de conversion de A à T, et pas de conversion de T vers A car T est const B. Les règles en vigueur ne feront pas de const A le common_type dans ce cas. On y va pour un P0.
Dans un cas comme celui-ci, les règles de déduction ne semblent pas être les mêmes pour tous les compilateurs :
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> auto f(typename A<T>::X) -> typename T::X;
template <class T> void f(...) { }
void h() {
f<int>(0);
}
Semble qu'il faille arrêter la déduction lors du premier échec rencontré, ce qui soulève la question de l'ordre des tests. Daveed Vandevoorde n'aime pas l'idée de « premier ». Richard Smith dit que devant un template friend dans une classe et sa définition ailleurs, l'ordre... est obscur...
Davis Herring signale des risques de violation d'ODR si des définitions distinctes apparaissent dans des unités de traduction distinctes, mais Daveed Vandevoorde estime que ce cas serait malformé.
P0, pour Jens Maurer.
Ici, la λ copie l'adresse mais ne bénit pas l'espace résultant :
#include <new>
int bar() {
alignas(int) unsigned char space[sizeof(int)];
int *pi = new (static_cast<void *>(space)) int;
*pi = 42;
return [=]() mutable {
return *std::launder(reinterpret_cast<int *>(space));
}();
}
Thomas Köppe penche pour un comportement indéfini. Richard Smith suggère un exemple.
Soit ceci :
struct Cat {};
struct Dog { operator Cat(); };
Dog d;
Cat c(d);
Peut-on permettre Copy-Elision ici? Il semble manquer du texte pour le permettre. Richard Smith s'en chargera.
Les règles de déduction de types sont trop complexes pour être raisonnables. Jens Maurer travaille sur quelque chose. P1.
Ce qui suit semble bien formé, malgré l'affectation privée dans A :
class A {
private:
A& operator=(const A&);
};
class B : virtual public A {
public:
B& operator=(const B &src);
};
class C: public B {
public:
void f(const C* psrc) {
*this = *psrc;
}
};
La question de l'affectation des parents virtuels indirects ou non ne semble pas claire dans le texte. La question soulevée ici est celle des parents virtuels directs. Mike Miller le fera.
Jasette avec Hubert Tong, puis petite marche. Un petit plat pas cher de nouilles au poisson, récupérer ma valise, marche vers la gare, croisé Capitaine America et Spider-Man, travaillé un peu, jasé avec Paul Preney quelques minutes, puis le train et quelques épisode de CppCast.