gasche a écrit 1151 commentaires

  • # Adopté à l'essai

    Posté par  . En réponse à la dépêche Nouvelle version d’autojump. Évalué à 2.

    Le descriptif est un peu tentant, alors j'ai décidé de l'essayer. Pour l'instant il ne sert à rien (pas de base), mais il n'est pas du tout intrusif.

    Je regrette l'utilisation de github, hébergeur propriétaire, comme plateforme principale du projet, alors qu'il existe des forges libres ou gitorious qui sont aussi de bonne qualité.

  • [^] # Re: Avec historique

    Posté par  . En réponse à l’entrée du suivi Permettre d'éditer son commentaire. Évalué à 1 (+0/-0).

    Franchement j'utilise quotidiennement des forums avec possibilité d'édition, et on n'a pas de problèmes de ce genre. Quand quelqu'un fait remarquer une erreur, la personne qui corrige pense à mettre un petit message en bas "Edit : merci machin, j'ai corrigé", voir à utiliser un style où l'ancienne version reste apparente dans le message (style "UNIXW Linux"), et tout le monde comprend.

  • # Avec historique

    Posté par  . En réponse à l’entrée du suivi Permettre d'éditer son commentaire. Évalué à 2 (+0/-0).

    Je souffre beaucoup personnellement de l'impossibilité d'éditer ses messages. Je relis avant publication, mais je trouve toujours un truc à dire en plus ensuite, ou une clarification à faire.

    Si vous avez peur des abus (ce que je trouve curieux puisque rien n'indique qu'il n'en aurait, les participants sur LinuxFR ne sont pas spécialement de mauvaise foi), le plus propre est de conserver pour chaque post un historique complet, comme c'est fait sur StackOverflow il me semble.

  • # Choix beaucoup trop restreints

    Posté par  . En réponse au sondage Où exercez-vous votre art ?. Évalué à 10.

    À voir ce sondage, on dirait que tous les visiteurs sont censés faire du service pour des non-techniciens. Où sont passés les autres ?

    • étudiants
    • chercheurs
    • hobbyistes sur leur temps libre
    • et surtout, les gens qui sont payés pour, vous savez, développer des logiciels ?
  • # Ergonomie et sécurité

    Posté par  . En réponse à la dépêche Jeudi du Libre de Bruxelles dédié à l’ergonomie. Évalué à 1.

    Je profite d'une mention de l'ergonomie dans le logiciel pour faire de la pub pour un article qui m'a beaucoup plu et dont le contenu mérite, je pense, d'être connu plus largement par les concepteurs d'interface utilisateur. Il s'agit de User Interaction Design for Secure Systems de Ka-Ping Yee, 2002. Il décrit des principes d'interface utilisateur qui, s'ils ne sont pas respectés, peuvent porter atteinte à la sécurité. J'ai même (auto-promotion sans scrupule) écrit un court billet sur le sujet.

  • [^] # Re: Et Policykit là-dedans

    Posté par  . En réponse à la dépêche Capsicum, une séparation fine des privilèges pour UNIX. Évalué à 3.

    PolicyKit reconnaît le fait que le système Unix habituel ne permet pas d'appliquer efficacement le Principle of Least Privilege, et ça fait un point commun avec Capsicum.

    Il est plus orienté vers un accès à des droits supplémentaires pour un utilisateur, le genre de chose qui demanderait des droits root d'habitude. Capsicum peut faire ça, mais il est aussi (surtout ?) pensé pour restreindre les droits utilisateurs au strict minimum. C'est faisable avec le modèle PolyciKit, en partant d'un utilisateur anonyme sans droit qui dialogue par PolicyKit pour obtenir plus de droits, mais c'est sans doute pas vraiment prévu pour en l'état donc moins pratique. Plus généralement, Capsicum permet de limiter facilement les droits existant au strict minimum, alors que PolicyKit décrit seulement comment obtenir plus de droits (ce que Capsicum permet aussi).

    Au niveau du fonctionnement, PolicyKit n'est pas un nouveau modèle d'accès, implémenté au niveau du noyau ou de bibliothèques de base. C'est seulement un serveur de messages qui est pensé pour faire dialoguer des applications sans droits et des applications avec droit, pour demander aux applications avec droits de faire des choses pour les sans droits (ce qui revient à leur "prêter" ponctuellement ce droit). C'est donc plutôt une question d'organisation du transfert de droit, qu'un choix technique sur le mécanisme de droit d'accès. Dans un système à capacités, il faudra aussi de tels mécanismes d'organisation, et les solutions retenues habituellement utilisent, comme PolicyKit, le passage de messages. Par exemple, la situation du dialogue de choix d'un fichier décrite dans la news est typique d'un dialogue entre un programme sans droits (Sur le système de fichier) et un utilitaire système privilégié (le programme de choix de fichier), qui fonctionne par passage de message.

    Par contre, au-delà de l'aspect 'passage de message', la façon dont PolicyKit et les systèmes de capacités représentent les droits est très différente. PolycyKit utilise un système tout à fait classique de style "matrice d'accès" : on dit "je suis le SUjet, je veux faire telle Action sur tel Objet", et Polycikit autorise ou non. La programmation de système utilisant Policykit se fait donc en se posant des questions comme "qui a le droit d'accéder à tel Objet ?", "Quelles sont les Actions que l'on autorise pour tel Sujet" ? En particulier la gestion des sujets est assez grossière, c'est essentiellement l'utilisateur au sens des systèmes Unix, on pourrait faire plus fin (par exemple on peut temporairement utiliser un processus donné à faire une action donnée en envoyant à un système privilégié un message du style "maintenant si on te demande l'autorisation pour le pid truc, tu acceptes", et en changeant d'avis au bout d'un moment) mais ce serait, dans la plupart des cas, galère à programmer.
    Avec les systèmes à capacités, le point de vue sur la gestion des droits est fondamentalement différent. Les droits et les actions sont couplés, et les processus se les passent entre eux selon le besoin, sans passer par un "système de droit" intermédiaire. On se demande donc "de quel droit tel processus/programme/système/utilisateur va-t-il avoir besoin ?", on les lui donne, et après c'est à lui de les répartir avec les autres processus avec qui il est en contact. La gestion des droits est donc naturellement plus fine et plus dynamique, mais aussi moins structurée (d'est ensuite aux applications d'utiliser des patterns de transfert de droits qui suivent une politique haut-niveau donnée). La question de "tel Sujet a-t-il le droit d'utiliser cette Capacité/Action ?" n'a pas de sens : soit il possède la capacité et alors il lui suffit de l'activer pour effectuer l'action, soit il ne la possède pas et il ne peut même pas essayer.

  • [^] # Re: option -Ofast

    Posté par  . En réponse à la dépêche La version 4.6 du compilateur GCC est disponible. Évalué à 2.

    cat /proc/cpuinfo | grep sse
    
  • [^] # Re: Si surcouche de langage nécessaire, changer de langage ?

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 0.

    Honnêtement, je l'ai déjà dit mais je pense que n'importe quelle syntaxe pensée pour être vaguement utilisable peut être apprise en quelques heures/jours de pratique. Alors oui, une syntaxe familière ça fait baisser un peu la barrière d'adoption, mais les gens qui ont deux sous de jugeote devraient savoir passer outre et faire un effort, si le langage derrière en vaut la chandelle.

  • [^] # Re: Pour ceux qui ne sauraient pas ...

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 1.

    Il y a une différence très importante entre les stratégies qui évaluent sous les lambdas/fonctions et celles qui ne le font pas. Les langages de programmation ne le font, dans l'écrasante majorité des cas, pas. Donc quand on dit "strict de gauche à droite" on veut dire qu'on évalue la fonction jusqu'à un lambda, mais pas en dessous, et ensuite les arguments de gauche à droite. Ce n'est pas la même chose que "applicative order" (qui réduit sous les lambdas). Je ne connais pas la terminologie "fully strict".

    Par exemple, le programme OCaml suivant :

    let make_counter () =
      let count = ref (-1) in
      fun () -> (incr count; !count)
    

    N'a aucun sens en "applicative order", puisqu'il renvoie toujours 0.

  • [^] # Re: Dommage pour les variables de motifs

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 2.

    Réponse à soi-même : la situation pourrait changer puisque l'auteur a l'air d'accord pour changer les choses à ce niveau.

  • [^] # Re: Si surcouche de langage nécessaire, changer de langage ?

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 2.

    Je ne comprends pas en quoi la syntaxe Erlang serait moins agréable à utiliser que la syntaxe Ruby. Elles sont différentes, et clairement une personne habituée à l'une des deux va la préférer par familiarité, mais je ne vois rien qui ne puisse devenir "agréable" après un moment d'acclimatation. Est-ce qu'il y a des points objectifs qui te font dire que la syntaxe de Ruby est "plus agréable" (il faut justifier en quoi) que la syntaxe Erlang ?

    Les deux défauts que j'ai cité dans mon premier message sont en fait des soucis au niveau de la syntaxe abstraite : il y a des choses qu'on ne peut simplement pas écrire, sous la forme Erlang tout comme sous la forme Ruby; je n'ai aucun jugement particulier sur la syntaxe concrète (choix des signes de ponctuation, des conventions lexicales, des mots-clés, etc.).

  • [^] # Re: Si surcouche de langage nécessaire, changer de langage ?

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 7.

    La syntaxe de Erlang a quelques défauts qu'on peut expliquer par son évolution historique en partant de celle de Prolog. Cependant, les gens qui disent "la syntaxe Erlang est trop difficile à apprendre" sont des flemmard-e-s qui n'ont pas essayé de coder en Erlang plus de quelques heures d'affilée.

    Si on s'intéresse au langage Erlang, la syntaxe ne pose absolument pas problème, et le langage n'est pas spécialement difficile à apprendre (d'ailleurs il existe cet excellent livre de Joe Armstrong, dont la première partie (PDF) est disponible en ligne).

    Le coup de la syntaxe facile c'est un argument marketing pour faire plaisir aux rubyistes, pas une raison de fond. La réalité c'est juste que c'est le projet "for fun" d'un gars qui connaît très bien Ruby et un peu Erlang, et qui avait envie de voir ce que ça donnait, un mélange des deux. Il n'y a pas à chercher plus loin.

  • [^] # Re: Un dernier petit pas pour C++0x

    Posté par  . En réponse à la dépêche La version 4.6 du compilateur GCC est disponible. Évalué à 7.

    En parlant du temps d'édition des liens, le linker Gold semble maintenant être un citoyen à part entière de l'écosystème GCC; il est mentionné à plusieurs reprises dans les changelogs.

  • # Merci

    Posté par  . En réponse à la dépêche La version 4.6 du compilateur GCC est disponible. Évalué à 6.

    Comme d'habitude, merci patrick_g pour cette excellente dépêche. Avant sa sortie, j'ai lu les "change notes" officielles, mais il est beaucoup plus difficile d'en distinguer les changements importants.

  • [^] # Re: c'est moi ou bien...

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 3.

    Merci (ça fait toujours plaisir :p ) mais, dans l'autre sens, je n'ai pas terriblement insisté sur la question parce que je trouve qu'à partir du moment où on utilise la spécialisation pour avoir une implémentation efficace ou le pretty printing qui convient, on a en fait deux concepts, les maps générales et un "cas particulier optimisé" qui est essentiellement un tableau classique "caché", et le fait de dire "mais c'est la même chose" n'a pas énormément de sens.

    Par contre, ce qui a du sens et est utile, et que l'on peut obtenir par différentes méthodes, est de s'assurer que le tableau permet toutes les opérations que l'on a sur les maps. La technique "type map général + spécialisation" le permet, mais on pourrait aussi avoir les deux concepts séparés et proposer un "proxy" pour voir tout tableau comme une map (en implémentant les méthodes des maps par dessus les opérations des tableaux, plutôt qu'en convertissant les données, pour des raisons de performances temps et mémoire).

    De toute façon, mon message initial qui a lancé tout ce débat était juste une remarque sur le fait que les maps sont utiles puisque les tableaux, qui sont une forme d'association clé-valeur, sont très utilisés. C'est vrai indépendamment de savoir si on peut implémenter les tableaux comme map, etc. Ceci dit, la discussion qui s'est ensuivie reste intéressante.

  • [^] # Re: c'est moi ou bien...

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 5.

    Probablement parce que les objets permettent de contourner gracieusement tous les problemes que t'as mentionne juste au dessus. Les tableaux sont des objects, certes, mais je peux faire string[5]='t' sur une chaine que je suis pas cense modifier et me retrouver avec un beau depassement de pointeur en cadeau bonux. Bon courage pour faire pareil avec un object.

    Si les tableaux sont des objets, on peut "faire pareil" avec des objets, par définition. Tu n'as pas l'impression de te contredire ?

    Le problème n'est pas de savoir comment sont stockées les données en mémoire, mais quelle interface tu fournis pour les manipuler. Si tu donnes à ton objet la même interface qu'un tableau, tu as les mêmes problèmes qu'avec un tableau, la concision de la syntaxe en moins.

    Par exemple, les "problèmes UTF" que j'ai cité viennent du fait que, pour des chaînes UTF, la sémantique de l'indexation des caractères n'a pas vraiment de sens : quand tu dis str[1], ça peut vouloir dire le deuxième octet, ou le deuxième code point, et ça peut dépendre de quelle genre de normalisation est utilisée. Le problème fondamental c'est d'imaginer que tu as une opération d'accès à un index donné. Si ton objet te permets d'écrire des 'subrange' délimitées par des indices numériques, ça va poser des problèmes avec Unicode, tout autant que les 'slices' de Go.

    De même, c'est évident mais si ton objet ne fait de vérification quand tu accès à un indice de la chaîne, il peut provoquer des segfault aussi.

    Le fait de dire "c'est un objet" ne change rien et n'apporte rien, la question est de savoir quelle est l'interface proposée, et quel est le comportement garanti (vérifications d'accès ou pas, etc.).

  • # Dommage pour les variables de motifs

    Posté par  . En réponse à la dépêche Elixir, enfin une syntaxe agréable pour Erlang ?. Évalué à 3.

    Reia corrigeait ce qui est à mes yeux un des plus gros problèmes de syntaxe de Erlang, l'impossibilité d'avoir des variables toujours liantes dans les motifs (cf. cette discussion). Elixir ne fait rien à ce niveau, ce que je trouve dommage.

  • [^] # Re: c'est moi ou bien...

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 4.

    C'est un post ironique, ou tu trouves sérieusement que [string substringWithRange: NSMakeRange(2,8)] c'est beaucoup mieux que string[2:8] ?

    Je suis d'accord avec le fait que présenter les chaînes comme des tableaux n'est pas une idée géniale, en regard des difficultés importantes soulevées par UTF, mais aussi par la supériorité en pratique de structure immutables et facilement concaténable comme les ropes pour les manipulations de chaînes. Mais je n'ai pas compris le sens de l'argument "les objets c'est mieux" (de toute façon dans la plupart des langages objets, les tableaux sont aussi des objets, donc bon...) et des exemples de code qui suivent.

  • [^] # Re: Testez-le, ensuite vous pourrez critiquer

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 3.

    Oui, nous sommes d'accord.

    Si j'ai évoqué les méthodes de compilation des langages "très dynamiques" (que ce soit par JIT ou profile-based compilation) c'est pour montrer qu'on peut avoir une sémantique qui semble impliquer des appels indirects, et quand même une implémentation performante derrière, de nature à satisfaire les personnes exigeantes.

    Après, ça ne veut pas dire que l'implémentation effective du langage à un instant donné effectue ces efforts d'amélioration des performances. Dans ce sens ta question sur l'implémentation actuelle de Go est tout à fait pertinente. Mais je pense que sans invoquer le spectre du "sufficiently smart compiler" on peut juger que Go a une forte marge de manœuvre là-dessus et qu'il serait dommage de juger le langage (qui est avant tout une sémantique) sur des détails d'implémentation de ce type.

    L'inconvénient dans tout ça, c'est la perte de la predictibilité de la copmilation. Plus le compilateur est malin, plus il est difficile pour le programmeur d'être certain de ce qui va se passer. Mais c'est aussi le coût à payer pour une expressivité plus forte (car dans le fond, si on ajoute une indirection ici, ce n'est pas pour le plaisir, c'est parce que ça permet de mieux écrire des programmes).

  • [^] # Re: Testez-le, ensuite vous pourrez critiquer

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 2.

    Évidemment, j'ai oublié la citation qui tue de l'article :

    Although compiler techniques appear promising, we found that profile-based and dynamic prediction techniques were clearly better.

  • [^] # Re: Testez-le, ensuite vous pourrez critiquer

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 4.

    Ce qu'on fait les gens de Self que j'ai déjà cité précedemment, au tout début des années 90, c'est d'utiliser des techniques d'inlining agressif des méthodes appelées, combinées à du JIT. Du code natif inliné est plus performant qu'un appel direct.
    Après, ça ne vient pas gratuitement, il faut tout un mécanisme d'instrumentation pour repérer les méthodes à inliner, le JIT a aussi un coût, etc. Je ne prétends pas que c'est plus rapide dans tous les cas, mais qu'on peut obtenir des performances équivalentes dans le cas général. Par ailleurs, ces optimisations dynamique sont souvent plus efficaces en pratique que les optimisations statiques faites par les compilateurs, puisqu'il y a beaucoup de cas où un raisonnement statique n'est pas possible mais où l'instrumentation donne des prédictions extrêmement précises. Cf. par exemple cet article sur le C++, qui s'inspire du travail fait sur Self : "Reducing Indirect Function Call Overhead In C++ Programs", Brad Calder and Dirk Grunwald, 1994.

    Par ailleurs, je crois que tu te fourvoies sur le sens du mot "système" dans "programmation système". Dans la bouche des créateurs de Go, je pense qu'il ne s'agit pas d'écrire le gestionnaire de mémoire d'un noyau d'OS, mais plutôt de toute la partie "userland non graphique" qui se trouve au dessus du noyau. Et qui a plus besoin d'outils fiables qui permettent de programmer de larges systèmes que d'une élimination prédictible des appels indirects.

  • [^] # Re: c'est moi ou bien...

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 1.

    C'est vrai que l'opération "tri de la map de façon à ce que l'ordre des clés corresponde à l'ordre des valeurs" n'est pas très naturelle (parce qu'elle change les associations clé-valeur). Mais on pourrait très bien l'implémenter sur les maps de façon efficace.

    Est-ce que la séparation map/tableau permet vraiment d'"optimiser" ça ? Si je définissais les tableaux dans mon langage comme des maps (qui respectent les contraintes déjà données), et implémentait cette opération de tri par dessus, il n'y aurait pas de problème, si ?

    (Un truc que je vois c'est au moment du pretty-printing, on a envie de voir s'afficher par exemple [|1;2;3|] plutôt que {0:1; 1:2; 2:3})

  • [^] # Re: Testez-le, ensuite vous pourrez critiquer

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 5.

    Certes, dans le domaine de l'embarqué, les langages à GC actuels ne sont pas de bons outils. Mais ça ne change rien à ce que j'ai dit : les techniques disponibles de gestion automatique de la mémoire en C ou en C++ sont plus lentes que les techniques équivalentes en Java ou en OCaml par exemple. D'ailleurs, l'article que tu as cité le dit lui-même, en première page :

    Previous researchers have measured the runtime performance and space im- pact of conservative, non-copying garbage collection in C and C++ programs [...]. Extrapolating the results of studies with conservative collectors is impossible because precise, relocating garbage collectors (suitable only for garbage-collected languages) consistently outperform conservative, non-relocating garbage collectors.

    Dans mon message je n'ai fait aucune comparaison de performances entre des mécanismes de gestion de mémoire automatique et de gestion de mémoire manuelle (puisque ce sont deux choses différentes, qui devraient être utilisées pour des usages différents). J'ai comparé la performance des gestionnaires automatiques disponibles dans différents langages. Et j'ai constaté que des langages obsédés par le fait de pouvoir tout contrôler de ce qui se passe au runtime comme le C ou le C++ (obsession bien visible, peut-être à raison, dans le message auquel je réponds), les mécanismes bas niveau introduits pour permettre ce contrôle fin peuvent aussi jouer contre les performances à plus grande échelle, en rendant non sûr des techniques d'implémentation performantes qui seraient possible en leur absence.

    Par ailleurs, si on doit vraiment en arriver là, je tiens quand même à préciser que l'article que tu cites ne donne aucun chiffre solide sur la comparaison entre gestion manuelle et gestion automatique de la mémoire. Je ne veux pas dire que les mesures effectuées sont fausses, mais qu'elles mesurent quelque chose qui n'arrive jamais en pratique : on prend un programme avec GC, on le fait tourner pour calculer où peuvent/doivent être libérées les variables, et on insère ensuite magiquement des malloc/free vers un custom allocator ultra optimisé à ces endroits là. L'"arnaque" (qui n'est pas du tout malhonnête, l'auteur ne prétend pas permettre de faire des comparaisons entre C et des langages collectés) c'est que dans un vrai programme à gestion manuelle, le programmeur ne peut pas se permettre en général d'insérer magiquement les malloc à l'endroit optimal. Il utilise des techniques bien connues pour faire du code fiable en présence d'allocation manuelle (des "design patterns" du malloc/free si on veut), comme les RIAA (allocation et destruction suivant la structure lexicale du programme) ou d'autres conventions qui sont uniformes et maintenables, mais du coup plus du tout optimales, et donc utilisent plus de mémoire que l'exemple idéal mesuré dans l'article.

    Enfin, avec des systèmes de type plus puissants on peut avoir des systèmes de gestion de mémoire automatique qui n'ont pas besoin de tout allouer sur le tas, et donc d'utiliser un GC aussi souvent. Je t'invite à te renseigner par exemple sur le langage ATS, qui utilise des types linéaires et peut s'en servir pour décider d'allouer sur la pile. Bien qu'utilisant un GC, des comparaisons de performance avec le C te montreront qu'il est globalement aussi rapide, et utilise en général moins de mémoire.
    Bien sûr (attention petit troll pour le fun), ça c'est un langage de recherche avec de la vraie innovation dedans, pas du réchauffé comme Go, alors attention, il faut brancher son cerveau.

  • [^] # Re: c'est moi ou bien...

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 1.

    Oui, d'ailleurs tu notes le "essentiellement" (prendre de la distance) et le fait que ce n'est pas la même chose en Go.

    Maintenant si tu pouvais me donner un exemple d'opération qu'on fait sur un tableau qu'on ne pourrait absolument pas faire sur un map dont les clés sont "énumérables" (ou carrément indicées par 0..N-1) et à accès en temps constant, et qui sont absolument indispensables, je suis intéressé.

  • [^] # Re: Testez-le, ensuite vous pourrez critiquer

    Posté par  . En réponse à la dépêche Quelques nouvelles rapides du langage Go. Évalué à 2.

    Pour information, le fait que toutes les classes qui ont les bonnes méthodes respectent automatiquement l'interface est ce qu'on appelle précisément le "structural subtyping", par rapport au "nominal subtyping" utilisé dans la plupart des langages OO mainstream. "structural" puisque c'est la structure des objets (l'ensemble des méthodes exposées et de leur type) qui décide la relation de sous-typage, et pas des déclarations explicites et "nominales" au niveau de la déclaration de la classe.

    Ce n'est pas exactement nouveau, les différences entre ces deux techniques (qui ont chacun avantages et inconvénients, la structurelle étant généralement considérée comme meilleure mais un peu plus complexe) ont été débattues à mort. Pour donner un exemple, la couche objet de OCaml, apparue au tout tout début des années 2000, utilise le sous-typage structurel.

    (Le lien avec les templates C++ est plus que ténu : les templates n'ont pas de rapport avec le sous-typage, et le comportement extrêmement ad-hoc qui permet de le faire croire ici est une conséquence (parmi d'autres) de leur stratégie de compilation par ailleurs extrêmement pénible pour un usage normal.)