[code] Trouver les erreurs

Posté par  (site web personnel) . Édité par BAud, Snark, Benoît Sibaud, palm123, RoPP, M5oul, rootix, TBTB, Nicolas Boulay et ZeroHeure. Modéré par rootix. Licence CC By‑SA.
70
14
jan.
2015
Technologie

Le récent problème d'OpenSSL et de ses failles peut nous avoir rendu dubitatifs quant à la supposée meilleure qualité des logiciels libres.

Cette dépêche se veut un petit rappel sur ce qui impacte la qualité d'un programme informatique, et de ce que l'on peut en déduire pour la communauté libre, et open source.

Sommaire

État des lieux des méthodes utilisées dans l'industrie

Depuis que l'informatique existe (soit environ 40 ans), les erreurs ont toujours existé. L'eau coulant sous les ponts, des méthodes informelles, puis formelles ont vu le jour : tests de non-régression, tests unitaires, revue de code informelle, prototypes, etc.

Ces dernières années, les tests unitaires se généralisent, et le programmeur moyen se sent bien plus à l'aise pour changer son code quand les tests unitaires disent que tout va bien.

Est-ce la panacée ? Est-ce suffisant ?

L'industrie s'est posé la question depuis longtemps (tels qu'IBM, Microsoft, la NASA, etc.).

Voici un graphique[1] récapitulant le taux d'erreurs détectées grâce à plusieurs méthodes (NdM: données antérieures à 2004). Les noms sont masqués dans le graphique, mais ils sont détaillés en dessous de celui-ci : cela permet de deviner et surtout d'être surpris :

Taux d'erreurs par méthode

A: Revues de conception (informel)
B: Inspection de conception (formel)
C: Revue de code (informel)
D: Inspection de code (formel)
E: Prototypage
F: Vérification personnelle de code
G: Tests unitaires
H: Test d'une nouvelle fonction (ou d'un nouveau composant)
I: Tests d'intégration
J: Tests de régression
K: Tests systèmes
L: Béta test à faible volume (moins de 10 sites)
M: Béta test à haut volume (plus de 1000 sites)

Combien d'erreurs ?

À partir de combien d'erreurs peut-on dire qu'un logiciel est de bonne qualité ?

De manière générale, ce taux varie entre 1 et 25 défauts pour 1 000 lignes de code. La plupart des projets sont dans cette plage, mais certains projets sont mieux ficelés que d'autres : le taux de défauts au sein du code de la navette spatiale américaine est estimé à zéro sur 500 000 lignes de codes [2].

Répartition des erreurs

Avec de telles données, il est possible de supposer, en première approximation, qu'un projet a un niveau de défaut de dix pour 1 000 lignes de code. De fait, il semble naturel de penser qu'il y a sûrement un défaut de caché toutes les 100 lignes.

L'erreur de ce raisonnement est l'hypothèse d'équirépartition des erreurs, qui est malheureusement fausse. En effet, on retrouve l'adage du « 80/20 », c'est-à-dire que 80 % des défauts se retrouvent dans 20 % des classes ou fonctions [3].

Par exemple, Carpers Jones a identifié 31 classes sur les 425 du code de l'Information Management System d'IBM qui étaient un nid d'erreurs particulier. Elles ont été corrigées ou ré-écrites, ce qui a diminué les coûts de maintenance de 45 % et divisé par dix le taux de plaintes (pas juridiques) venant des utilisateurs.

Combos

Le graphique précédent montre que certaines méthodes sont meilleures que d'autres, tels qu'une bêta très distribuée, le prototypage, l'inspection de code formelle, l'inspection de la conception de manière formelle ou encore les tests unitaires.

Néanmoins, chaque méthode ne va pas détecter les mêmes défauts qu'une autre. Certaines ont des lieux communs, d'autres se complètent.

Conclusions

Grâce à ces quelques informations, on peut en tirer quelques conclusions pour les projets que l'on peut trouver dans la communauté.

Le projet écrit par une seule personne

Développer seul n'est pas simple, car la majorité des méthodes qui marchent le mieux demandent la participation d'autres personnes.
Néanmoins, prototyper son architecture (et le publier), ainsi que des tests unitaires permettent de se distinguer et de sauver les meubles (si la couverture des tests est proche de 100 %, en terme de lignes testées, non de fonctions).
Quelques utilisateurs peuvent également grandement améliorer le taux de détection d'erreurs, ce qui encourage à faire des versions assez rapidement.

Néanmoins, écrire des tests unitaires est gourmand en temps, pour un résultat plutôt contrasté : passer plus de temps à prototyper et écrire quelques tests mieux choisis est à considérer.

Le projet par une équipe réduite, mais viable (moins de 10 personnes)

En plus des points précédents, il devient possible de mettre en place une inspection de code formelle (basée sur des listes de choses à vérifier, avec retours d'information et amélioration des dites listes) sur la conception et le code. L'idée étant que l'algorithme est soumis aux autres, dont les retours sont pris en compte, de même avec le code.

Ce n'est pas forcément plus lent, puisque le nombre de défauts à corriger sera plus réduit par la suite et corriger tardivement est souvent long et coûteux [4].

Projets de grande envergure

C'est exactement pareil, mais les choses peuvent tourner plus facilement.

Code déjà écrit, tout le monde peut le lire !

La lecture de code déjà écrit n'est que très rarement aussi efficace que l'inspection formelle avant publication de code par plusieurs personnes. La NASA a déterminé que cela permettait de trouver environ 3 défauts par heure d'effort. On peut supposer qu'un programmeur moyen n'est pas aussi bon qu'un programmeur moyen de la NASA, ce qui tend à demander énormément de temps et d'envie.

Mais, l'histoire d'OpenSSL nous a montré que le temps et l'envie ne semblent pas vraiment être là, une fois le code écrit.

Fuzzing ou test de résilience

En sécurité informatique, il est possible de tester un logiciel dans des conditions non prévues lors de la conception et d'en observer le fonctionnement, c'est ce que l'on appelle des tests à conditions aléatoires, mais il peut être préférable de les nommer tests de résilience.

Tester la résilience d'un logiciel est relativement simple et ne demande pas d'en connaitre les moindres rouages, mais ce n'est pas toujours quelque chose de voulu. Voici deux exemples opposés qui permettent de comprendre que c'est plus un choix de conception, mais pas nécessairement une manière d'améliorer la qualité du code (cela reste un test automatique, avec ses avantages et défauts).

Firefox 35 vient de sortir, et tester sa résilience est bienvenu : si une page html est mal-formée, il est plus sain d'essayer de l'afficher tout de même, que de planter en perdant les onglets de l'utilisateur. De manière générale, les algorithmes de cryptographie se veulent résilients aux attaques et, pourquoi pas, aux défauts d'implémentation.

À l'opposé, une machine à découpe plasma a tout intérêt à s'arrêter si une donnée non conforme se présente : il en va de la sécurité de l'opérateur. De manière générale, dans le domaine de la médecine, il est préférable que le programme soit correct plutôt que résilient.

On voit ici la mise en exergue de ce que « qualité » signifie d'un projet à l'autre.

Mot de la fin

Cette dépêche vous apporte simplement quelques chiffres pour y voir plus clair dans le monde de la qualité des logiciels en général.

Pour en savoir plus, il vous est conseillé de lire « Code Complete » par Steve McConnel (en anglais).

Notes

[1] : Mise en forme de la table 20-2 de Code Complete par Steve McConnel, deuxième édition (2004). Les barres d'incertitudes représentent le minimum et le maximum d'erreurs détectées pour chaque méthode, ce qui n'est pas forcément symétrique (réalisé avec matplotlib)
[2] : d'après Fishman, en 2006
[3] : Endres 1975, Gremillion 1984, Boehm 1987b, Shull et al 2002
[4] : Code Complete par Steve McConnel, deuxième édition (2004), p. 474.

Aller plus loin

  • # Méthodologie

    Posté par  (site web personnel) . Évalué à 3.

    Je trouve le sujet très intéressant et bien expliqué dans cette dépêche, merci.
    Cependant je me demande quelle a été la méthodologie appliquée pour parvenir à ces estimations : conditions réelles ? On test les différentes méthodes sur le même code ? Ou au contraire sur des codes et équipes différentes ? Une même équipe sur différents codes ? Etc.

    • [^] # Re: Méthodologie

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 14 janvier 2015 à 13:12.

      Plusieurs méthodes ont été utilisées : plusieurs équipes sur un même programme à faire, même équipe sur différents codes, mais aussi études sur du code contenant des défauts déjà connus, etc. Le sujet n'est que survolé dans la dépêche, mais c'est beaucoup plus détaillé dans Code Complete par exemple.

      C'est souvent tiré de codes réels d'ailleurs.

      • [^] # Petite erreur

        Posté par  . Évalué à 0.

        Petite erreur de frappe

        Cette dépêche vous apporte simplement quelques chiffres pour y avoir plus clair dans le monde

        Cette dépêche vous apporte simplement quelques chiffres pour y voir plus clair dans le monde

  • # graphique ?

    Posté par  . Évalué à 1.

    L'article m'intéresse, mais malheureusement je ne vois pas le graphique… est-ce normal ? d'autres gens ont le problème ?

    J'utilise firefox (Iceweasel 31), avec https-everywhere (et donc linuxfr en HTTPS).

  • # Méthodes formelles

    Posté par  . Évalué à 10.

    J'ai l'impression que ton graphique ne parle pas des méthodes telles que l'analyse statique (je me demandais si ce que tu appelles « inspection de code formelle » ne le recouvrait pas, mais on dirait que non).

    Ce sont des méthodes utilisées dans l'industrie : par exemple, Astrée a été utilisé pour le logiciel de vol des Airbus 1340, ou encore FramaC.

    Ce serait intéressant de voir où se placent ces méthodes dans ton graphe.

    • [^] # Re: Méthodes formelles

      Posté par  . Évalué à 1.

      Oui bonne question. Chez nous ils sont en train de déployer SonarQube, par exemple.

      • [^] # Re: Méthodes formelles

        Posté par  (site web personnel) . Évalué à 1.

        C'est peut-être l'occasion d'étudier, en interne, le type d'erreurs que vous allez détecter, et ce que cela représente en volume.

        À mon humble avis, ça reste une méthode de test de code après coup, et il y a fort à parier qu'un problème d'architecture, ou d'algorithme est plus facile à repérer en amont, mais un dépassement de cache, ou des accès mémoire bizarres sont mieux ciblées.

        Ce n'est qu'une solution qui doit être mise en synergie avec d'autres, puisque la méthode ultime n'existe pas (foutu théorème de Rice).

        • [^] # Re: Méthodes formelles

          Posté par  (site web personnel) . Évalué à 3.

          Ce n'est qu'une solution qui doit être mise en synergie avec d'autres, puisque la méthode ultime n'existe pas (foutu théorème de Rice).

          On peut s'en approcher, par exemple, si on réussit à programmer et prouver en Coq 99% (pourcentage à la louche) du programme dans les restrictions imposées par un langage non Turing-complet. Il restera, bien sûr, toujours un 1% où d'autres méthodes seront nécessaires. Après, je ne pense pas qu'il y ait beaucoup de programmes en dehors des systèmes vraiment critiques pour lesquels une telle approche soit raisonnable.

    • [^] # Re: Méthodes formelles

      Posté par  (site web personnel) . Évalué à 6.

      Je confirme, « l’inspection de code formel » de McConnell n'a rien à voir avec les analyses statiques et notamment les méthodes formelles. Le « formel » dans l'inspection de code, c'est qu'on suit une procédure codifiée.

      Côté analyses statiques, on distingue les approches non formelles, les bug finders et les approches formelles comme Astrée, Frama-C, la Méthode B, SPARK, etc. Les deux sont utiles, les bug finders sont plus facile à utiliser mais pouvant donner des faux positifs ou des faux négatifs. Les approches formelles donnent des garanties plus fortes (si pas d'alarme alors le logiciel est garanti sans un certain type de fautes) mais sont plus difficiles à utiliser (mais largement utilisables pour certains).

      Pour ceux que ça intéresse, je maintiens une liste de tous les outils libres formels. Il y a de tout, de logiciels ultra spécialisés à des environnements de développement et preuve pour une approche particulière : gulliver.eu.org/free_software_for_formal_verification.

      PS : Je ne vois pas le graphe, pourtant j'ai installé le certificat. Je vois bien les avatars.

  • # Tout pareil

    Posté par  (site web personnel) . Évalué à 10.

    Ça fait 3 ans que je pratique les revues de code et je trouve ça super. Le premier intérêt tel que cité dans la dépêche est que cela permet de trouver rapidement un paquet de bugs et des défauts d'architecture, globalement l'application s'améliore très vite. C'est en effet très rare qu'un commit ne reçoive aucun commentaire, ne serait-ce que pour relever des éléments qui sont acceptés mais pourraient poser problème dans d'autres situations. L'autre intérêt est que cela diffuse rapidement la connaissance du code et casse le cloisonnement par auteur. On n'hésite plus à modifier ou casser le travail d'un autre car grâce à la revue on a une bonne idée des tenants et aboutissants.

    Les tests unitaires sont pour moi un moyen de renforcer ce dernier point. Je ne pratique que depuis quelques mois et bien que ce soit souvent pénible d'écrire les tests je suis toujours ravi de les voir tomber, que ce soit parce que je les ai écrits avant le code client ou bien parce que je modifie une ancienne partie de l'application. Grâce à eux je sais que mes modifs sont cadrées et qu'on ne me laissera pas faire de bêtises.

    Code Complete est un excellent livre. Lisez-le.

  • # Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

    Posté par  . Évalué à 9.

    Je pense que développer des fonctionnalités est considéré comme bien plus important que d'avoir ces fonctionnalités fiable/sécurisée.
    Autrement on ne continuerai pas d'utiliser le C ou le C++ au lieu d'Ada (par exemple)..

    C'est un choix tout à fait compréhensible, mais ne prétendons pas que les logiciels libres soient spéciaux concernant la sécurité ou la fiabilité..
    J'avoue être tout de même surpris qu'OpenBSD qui est supposé mettre l'accent coté sécurité ait fait le même choix (utiliser un langage privilégiant la performance à la sécurité par défaut).

    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

      Posté par  (site web personnel, Mastodon) . Évalué à 7.

      J'avoue être tout de même surpris qu'OpenBSD qui est supposé mettre l'accent coté sécurité ait fait le même choix (utiliser un langage privilégiant la performance à la sécurité par défaut).

      Parce que la base de code C était déjà là dans les BSD et qu'ils n'ont par forcément tout ré-écrit from scratch.
      Et puis, coder un OS, c'est long alors certains doivent se dire que ce serait encore plus long en Ada :)
      Pour finir, il y a aussi le problème du runtime Ada qu'il faut porter pour pouvoir bénéficier de tous les avantages du langage.

      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

        Posté par  (site web personnel) . Évalué à 2.

        En vrai, c'est plutôt que Ada c'est très bien sur le papier, mais que c'est un tue l'amour à réussir à passer la compilation (les inconvénients de ses avantages). En effet, il est tout de même très frustrant de passer 1/2 journée à écrire son 1erHello World lorsqu'on découvre le langage.

        Au moins avec --pedantic de gcc, tu peux l'appliquer après que ton programme fonctionne et compile déjà, cela devient un jeu de retirer jusqu'au dernier warning et ça sert pour la suite. Compiler de l'Ada, c'est plutôt un parcours d'obstacle à chaque étape, sans être certain d'arriver au bout de la quête :/

        Les statistiques sont intéressantes : sur oholh^WOpenHub pour Ada a 880 projets recensés alors que les vrais langages ont deux ordres de grandeur de plus java, C et python, vu que le C++ arrive derrière… et que XML / HTML / CSS / shell script / javascript peuvent n'être vus que comme de la glue (même si une utilisation connexe de l'usage principal peut en faire un vrai langage).

        Bref, j'aime bien Ada et je regrette qu'il soit autant délaissé, à raison àmha :/

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  (site web personnel) . Évalué à 9.

          Si tu n'aimes pas les langages qui te trouvent les bugs à la compilation, c'est que tu n'as pas fait assez de programmation. ;-) En plus de l'Ada, tu devrais tester OCaml ou Haskell.

          L'Ada est largement utilisé pour les logiciels critiques dans le domaine ferroviaire (logiciels à bord des TGV, contrôle des trains au sols, métros automatiques), aéronautique ou spatial (Ariane).

          Moi aussi j'aime bien l'Ada et je regrette qu'il soit autant délaissé, à tord à mon avis.

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  (site web personnel, Mastodon) . Évalué à 5.

          En effet, il est tout de même très frustrant de passer 1/2 journée à écrire son 1erHello World lorsqu'on découvre le langage.

          T'exagères pas un peu là ? Si c'est pas le cas, c'est grave.
          Mais avouons que, contrairement à un langage de script, c'est vrai c'est plus dur, faut lire un minimum de doc.

          tu peux l'appliquer après que ton programme fonctionne et compile déjà, cela devient un jeu de retirer jusqu'au dernier warning et ça sert pour la suite.

          Pour moi, c'est tout l'opposé. Je préfère largement un truc qui ne compile pas et qui m'oblige à réfléchir mon code pour passer la compilation qu'un code qui compile avec une tétra-chiée de warning que personne ne voudra corriger.
          D'ailleurs, quand on compile le GCC, faut pas avoir peur parce que des warning, il y en a un bon paquet :)

          Sinon, j'aime bien ta définition des vrais langages :D
          Mention spéciale pour Java qui permet l'écriture très simple d'un Hello World, surtout pour celui qui ne sait pas ce qu'est une classe…

          • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

            Posté par  (site web personnel) . Évalué à 6. Dernière modification le 15 janvier 2015 à 22:03.

            T'exagères pas un peu là ? Si c'est pas le cas, c'est grave.

            bin non

            tu y réponds de toi même, d'ailleurs :

            Mais avouons que, contrairement à un langage de script, c'est vrai c'est plus dur, faut lire un minimum de doc.

            et compter le temps passé à faire un make qui va bien (vu que tu dois relancer la compil' souvent) + positionner les ; au bon endroit + trouver les use utiles pour afficher un truc à l'écran et positionner les ; au bon endroit (ah je l'ai déjà dit, mais ça m'avait tué ce truc et remémoré mes pires moments avec le Pascal…

            Au moins avec le C, j'ai eu moins de souci : en école d'ingé, en 1ère A il fallait coder en Pascal (Turbo Pascal de Borland…), je codais d'abord en C puis je traduisais ensuite en Pascal. En 2è A il a fallu faire les mêmes programmes, mais en C… bin je les avais déjà fait. En vrai, au secondaire, je lisais Pascalissime qui présentait des algos sympas, pleins de programmes en Math ou Physique, mais malencontreusement écrits en Pascal, je les recopiais méthodiquement ('fin l'algo) mais en C (Borland C++ avec un profiler au top et un compilo avec niveau de warning ajustable : au début j'en avais plein, une fois que le programme fonctionnait, je faisais une passe pour les retirer un à un pour en garder le minimum voire aucun, même si c'est peu possible en C vu que le cast est une mauvaise pratique et que j'en avais parfois besoin).

            Bref, Ada est très bien, il s'interface excellemment avec des bibliothèques écrites dans d'autres langages (un stub et c'est marre), mais bon sa gestion des ; encore plus erratique qu'en Pascal et qui bloque la compilation était super pénible. En C, ça compile jusqu'au bout au moins, même s'il faut s'appliquer des conventions pour éviter le cas classique du case par exemple, qui est la tarte à la crème du code qui ne fait pas ce que tu voulais faire (de ce côté, les exceptions d'Ada sont un vrai apport comparé au C qui ne l'impose pas et change d'un programmeur à l'autre… le goto étant une bonne manière de faire en C, la seule utilité du goto d'ailleurs…).

            une tétra-chiée de warning que personne ne voudra corriger.

            ça c'est une question de rigueur voire d'ego^Wfierté. Pour moi un programmeur qui est satisfait que cela fonctionne mais a une tétra-chiée de warning n'a pas d'ego, voire n'est pas un programmeur ;-) (surtout s'il ne sait pas expliquer pourquoi il a gardé ces warnings même après livraison, cela ne donne pas trop confiance à celui qui va devoir reprendre le code et le maintenir ensuite…).

            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

              Posté par  (site web personnel, Mastodon) . Évalué à 1.

              et compter le temps passé à faire un make qui va bien (vu que tu dois relancer la compil' souvent) + positionner les ; au bon endroit

              Alors avec Gnat, pas besoin de make sauf si tu as besoin de compiler du C.
              Si tu veux vraiment faire un beau truc, tu peux utiliser un fichier de projet Gprbuild mais il n'y a rien d'obligatoire.

              • trouver les use utiles pour afficher un truc à l'écran

              Pas plus dur que de trouver le bon include

              positionner les ; au bon endroit

              Tu parles justement du C et il se trouve qu'il y en a encore plus en C… Ne serait-ce que dans un for.
              Quand on est codeur C, le problème du point-virgule en Ada commence à s'apparenter à de la mauvaise foi.
              Surtout que si tu oublies un point-virgule en C, certes, il va jusqu'au bout mais tu sais pas trop ce qu'il compile au final.

              s'il faut s'appliquer des conventions pour éviter le cas classique du case par exemple

              Justement en Ada, il n'y a pas à s'appliquer des conventions pour ce genre de choses. Typiquement, un case doit couvrir tous les cas.

              Pour moi un programmeur qui est satisfait que cela fonctionne mais a une tétra-chiée de warning n'a pas d'ego, voire n'est pas un programmeur ;-) (surtout s'il ne sait pas expliquer pourquoi il a gardé ces warnings même après livraison, cela ne donne pas trop confiance à celui qui va devoir reprendre le code et le maintenir ensuite…).

              Tu dois pas souvent compiler un noyau Linux alors parce que sinon tu verrais que c'est pas plein de non programmeurs :D

            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

              Posté par  . Évalué à 8.

              la seule utilité du goto d'ailleurs…)

              Hum… désolé, ça sera du C++, pas envie de me coltiner à la main des vérifs de longueur de chaîne… mais:

              #include <string>
              #include <array>
              #include <cstdio>
              
              int main(void)
              {
                std::string foo;
                std::array<std::string, 5> bar { "azerty", "qsdfgh", "wxcvbn", "poiuyt", "mlkjhg" };
              
                std::array<std::string, 5>::iterator foo_it=bar.begin();
                goto first_stage;
              
                for( ; bar.end() != foo_it ; ++foo_it )
                {
                  foo += ";";
              first_stage:
                  foo += *foo_it;
                }
                return 0;
              }

              Enregistrer ça dans /tmp/test.cpp puis: clang++ -Weverything -std=c++11 test.cpp ; ./a.out
              donnera ceci:

              test.cpp:8:34: warning: generalized initializer lists are incompatible with C++98 [-Wc++98-compat]
                std::array<std::string, 5> bar { "azerty", "qsdfgh", "wxcvbn", "poiuyt", "mlkjhg" };
                                               ^
              test.cpp:8:36: warning: suggest braces around initialization of subobject [-Wmissing-braces]
                std::array<std::string, 5> bar { "azerty", "qsdfgh", "wxcvbn", "poiuyt", "mlkjhg" };
                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                 {                                               }
              2 warnings generated.
              azerty;qsdfgh;wxcvbn;poiuyt;mlkjhg
              

              Les warnings sont vraiment très cons puisque j'ai demandé expressément du C++11, mais passons.
              Le plus intéressant, c'est le résultat: "azerty;qsdfgh;wxcvbn;poiuyt;mlkjhg". Je suis curieux de voir un algo, sans goto, qui fasse la même chose sans, au choix:

              • mettre un if dans la boucle, et donc impact sur les performances (si c'est la boucle principale du programme, c'est dommage…),
              • dupliquer la partie de code avant le label, et briser le justifié Do Not Repeat Yourself, et augmente la taille du runtime,
              • créer une fonction qui ne sera appelée que 2 fois (en même temps, ça m'arrive de le faire pour des fonctions appelées une seule fois, certes, histoire de compartimenter le code) et qui nécessitera soit:
                • de l'inlining, mais ça augmente la taille du runtime
                • un jump avant le for et à chaque itération (tiens, je viens de penser qu'en fait, c'est pire que le if cette solution là…).

              C'est une vraie question: pour ce pattern la, comment faire sans goto? À efficacité maximale, j'entend. Et franchement, cet usage précis je ne le trouve pas sale… je sais plus qui, sur linuxfr me l'a fait découvrir. Au début j'ai essayé de répondre, mais au fur et à mesure je m'apercevais qu'aucun argument ne gagnais.
              Du coup, j'ai pas envoyé le message ;)

              Comme quoi, le goto, on le critique souvent, mais peut-être que ce qu'on devrait critiquer, ce sont les mauvais usages du goto. Maintenant, on peut dire la même chose des singleton, des template, de l'héritage (surtout l'héritage pour le coup!) voire même des classes. Toutes les techniques sont mauvaises si mal employées, mais ce n'est pas la faute à la technique, juste à son utilisateur.

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 1.

                C'est une vraie question: pour ce pattern la, comment faire sans goto?

                Avec un while, c'est pas possible (pas testé, toutes mes excuses si ça ne marche pas)?

                while(foo += *foo_it, foo_it++ != bar.end()) foo += ";";

                Aucune idée de ce que ça donne à l'exécution. À mon avis, le choix du C++ est assez paradoxal avec la micro-optimisation demandée.

                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  . Évalué à 2.

                  Avec un while, c'est pas possible (pas testé, toutes mes excuses si ça ne marche pas)?

                  Non tu aura un ";" à la fin.

                  À mon avis, le choix du C++ est assez paradoxal avec la micro-optimisation demandée.

                  Pourquoi ?

                  Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 4.

                    Non tu aura un ";" à la fin.

                    En fait, ça lançait une exception, il faut renverser les ++ (du coup, j'aurais dû tester):

                    while(foo += *foo_it, ++foo_it != bar.end()) foo += ";";

                    Ça donne le bon résultat, et je trouve ça beaucoup plus court et plus explicite que le goto.

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 1.

                    À mon avis, le choix du C++ est assez paradoxal avec la micro-optimisation demandée.
                    Pourquoi ?

                    Bah, tu as le choix entre une Ferrari et une berline ; tu choisis la berline (ce qui peut se justifier), mais pourquoi tenter de régler les suspensions au millimètre près? Si ton objectif est la performance, tu aurais dû choisir la Ferrari, puisque même bien affutée, tu ne pourras jamais égaler la voiture de course.

                    Par curiosité, le compilo ne détecte pas la duplication de code quand tu fais quelque chose comme:

                    foo += *foo_it;
                    for ( ; foo_it != bar.end(); ++foo_it) { foo += ";"; foo += *foo_it; }

                    Naïvement, j'aurais tendance à penser que c'est le genre de choses qui sont relativement faciles à optimiser, mais je me trompe certainement…

                    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                      Posté par  . Évalué à 2.

                      Bah, tu as le choix entre une Ferrari et une berline

                      Si le C++ est une berline, qui est la Ferrari? Le C, ou l'assembleur?
                      Je ne vois pas vraiment de raison pour que le C++ soit plus lent que le C.

                      Je vois 3 corrections à faire dans mon code, si j'avais vraiment voulu l'utiliser dans un vrai programme:

                      • vérifier que le tableau est pas vide (mais j'ai utilisé un array statique ici donc il n'y à aucun risque au runtime)
                      • utiliser des char[] dans l'array, et pas des std::string
                      • réserver correctement dès le début l'espace que le std::string occupera à la fin (on le connaît, puisque tout est statique, et au pire on pourrait le calculer) pour éviter les realloc.

                      Mais c'était censé être un code à la va-vite, rien de plus, pas un code parfait ;)
                      En tout cas merci pour ta solution.

                      Par curiosité, le compilo ne détecte pas la duplication de code quand tu fais quelque chose comme:

                      Aucune idée. Par contre je sais que le cerveau humain, lui, n'est pas toujours capable de fusionner un bout de copié/collé, surtout que tu peux avoir plus que quelques lignes de code. Encore une fois, ici, c'était un exemple trivial.

                      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                        Posté par  . Évalué à 5.

                        Je ne vois pas vraiment de raison pour que le C++ soit plus lent que le C.

                        Il y a plusieurs niveaux de réponse. Le premier niveau, évidemment, c'est que le C est (à peu près) valide en C++, et qu'il suffit de coder en C pour avoir les mêmes performances. Le deuxième niveau est que ça dépend ; en théorie, on peut faire plus de choses au C++ au moment de la compilation, et que sur des cas particuliers, C++ peut être plus rapide que C (il y a des exemples d'algorithmes qui peuvent même être résolus au moment de la compilation en C++ via des templates ou des constructions un peu complexes). Le troisième niveau, le "vrai" niveau, consiste à admettre que la richesse du C++, la programmation objet, la STL, etc, ont des contraintes qui ajoutent un coût significatif—et là, on est bien d'accord, on n'est pas à fonctionalités égales. Les fonctions virtuelles, ont un coût, par exemple. Par ailleurs, les idiomes du C++ sont plus lourds que le C ; par exemple, on a tendance à faire beaucoup plus de tests pour vérifier l'intégrité des classes ; il est également plus facile en C++ d'appeler du code inutile (constructeur par défaut…) involontairement.

                        utiliser des char[] dans l'array, et pas des std::string

                        Ce genre de trucs, par exemple, me semblent relever du fameux C/C++, une sorte de langage indéterminé qui mélange les idiomes des deux langages. Après, chacun fait ce qu'il veut, et il n'existe pas encore de religieux intégristes du C++. Mais personnellement je trouve que c'est dommage de perdre la sémantique (un std::string n'est pas un std::vector en C++) pour gagner un micropouillème hypothétique au moment de l'exécution (sans compter qu'il n'est pas impossible que le compilo détecte les concaténation de chaines constantes, et que plus le code est clair, plus le compilo est efficace).

                        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                          Posté par  . Évalué à 3.

                          sur des cas particuliers, C++ peut être plus rapide que C

                          Me semble avoir vu un papier sur l'utilisation de la fonction C sort, contre je ne sais plus quel algo générique C++ ou le C++ était effectivement supérieur. Mais supérieur à mon avis uniquement à l'implémentation standard C.

                          Le troisième niveau, le "vrai" niveau,

                          Je vois. Arguments intéressants, en effet, l'usage des fonctionnalités supplémentaires du C++ risque d'alourdir le programme en terme de performances. La RTTI, les exceptions (quoique, dans ce cas précis, je me demande quel est le plus lourd dans le chemin non-exceptionnel, entre un programme C++ et un programme C qui vérifie tout) et surtout, surtout les méthodes virtuelles… tout ça coûte cher.
                          Appeler du code sans en faire exprès est également simple. Trop simple même, et c'est probablement pour ce genre de raisons que Bjarne Stroustrup à dit «C++ has indeed become too "expert friendly"».

                          Pour la STL, à fonctionnalité égale, c'est à dire avec une struct C et son ensemble de fonctions accompagnatrices, je suis déjà plus mitigé. Pour vector et array, je ne vois pas de raison (je pense que c'est égal), pour std::list par contre oui, parce que c'est une implem de liste chaînée non intrusive. Bien qu'on puisse la réimplémenter en intrusif, je doute que ce soit la première étape que prendra un développeur C++. Dans le cas de map et set, je n'en sais rien du tout.

                          une sorte de langage indéterminé qui mélange les idiomes des deux langages.

                          Je vois. Donc pour toi, mêler les deux langages résulte dans un code bâtard. Personnellement, je considère qu'il s'agit de C++ pur, parce qu'un des axes de C++ c'est de ne payer que pour ce que l'on utilise (que ce soit les classes, les algo standards, la RTTI, les exceptions… un code C qui n'utiliserait que std::array et les casts plus sûrs de C++ deviendrait à mes yeux du C++).

                          il n'existe pas encore de religieux intégristes du C++

                          Ce serait dommage, compte tenu du fait que le C++ est un langage qui me semble plutôt pragmatique, notamment rien n'empêche l'usage de GC ou de tout objet (ah, si, il faut obligatoirement créer une fonction main pour appeler une méthode statique main de la classe principale… mais à part ça, je vois pas)..

                          Mais personnellement je trouve que c'est dommage de perdre la sémantique (un std::string n'est pas un std::vector en C++)

                          C'est vrai. Par contre je me demande s'il y a beaucoup de différences entre les implem des deux.

                          sans compter qu'il n'est pas impossible que le compilo détecte les concaténation de chaines constantes, et que plus le code est clair, plus le compilo est efficace

                          Je ne sais pas si le compilateur est capable de détecter qu'un membre d'une classe n'est jamais accédé (cas d'un string jamais modifié, par exemple, qui pourrait être remplacé par un std::array). D'ailleurs, il ne vaudrait mieux pas: si, au cours d'une modification d'un programme, un string passe en const, le compilo le remplace à la compilation par un array, ça risque de péter l'ABI sans raison.

                          Et je ne suis pas non plus persuadé que l'efficacité du compilateur soit plus importante quand le code est clair: il peut être clair pour son auteur, mais pas pour le compilateur. Il n'y à rien de plus débile qu'un compilo quand il s'agit de deviner ce qu'un programmeur essaie de faire après tout.

                          Je me trompe peut-être, mais est-ce qu'on n'en demande pas trop parfois au compilateur? Certes, pour des trucs (un paramètre d'une fonction non nommé et donc jamais utilisé par la fonction ne sera pas mis dans le binaire par exemple) on peut lui faire confiance, mais à un moment faire toujours confiance aux autres pour faire son propre job, me paraît délicat.

                          Dans le cas du goto que j'ai mis en exemple, il y avait effectivement une meilleure implémentation, celle avec le while. Pas de goto, donc un risque en moins, pas de répétition de code, donc maintenance moins dangereuse, et on évite de coller un if qui sera peut-être, ou pas, optimisé par le compilateur. Qui sera peut-être même bugué d'ailleurs (qui n'à jamais fait de faute d'étourderie dans un if?).
                          D'ailleurs, ce if, il ne sera pas optimisé par le compilateur en débogage, je me trompe? C'est peut-être une micro optim, c'est vrai, mais est-elle illisible? Et si ce n'est pas le cas, pourquoi ne pas l'utiliser?

                          • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                            Posté par  . Évalué à 4.

                            Me semble avoir vu un papier sur l'utilisation de la fonction C sort, contre je ne sais plus quel algo générique C++ ou le C++ était effectivement supérieur. Mais supérieur à mon avis uniquement à l'implémentation standard C.

                            En fait, la différence est dans la manière dont se fait l’appel à la fonction de comparaison. Avec qsort() en C, on passe par un pointeur de fonction. Avec std::sort, le compilateur va générer l’ensemble du code de tri, spécialisé pour la fonction de tri donnée. L’empreinte mémoire sera un peu plus grosse, mais en revanche on se passe du pointeur de fonction, l’appel au comparateur est plus rapide, au final on est gagnant.

                            Et C n’offre pas d’alternative autre que de réécrire l’algo spécialisé pour le type en question pour avoir les mêmes perfs. En C++, c’est le compilateru qui le fait pour toi.

                            De la même manière, une bibliothèque comme ublas (calcul matriciel) met une branlée à toute bibliothèque C pour toutes les opérations non spécialisées dans les libs C, grâce à l’utilisation d’expression templates.

                            J’avais lu un comparatif assez intéressant, je crois fait par les devs de scala au départ, sur les perfs entre C++, Scala, Java (je crois qu’il y avait un autre langage mais je ne me souvient plus lequel, peut-être go). La conclusion qui en ressortait était que le programme « naïf » écrit en C++ était plus lent que celui écrit naïvement en scala, et qu’après optimisations ils étaient à peu près équivalent. Ensuite, ils ont donné le programme à un gourou C++ (un vrai), qui a fait de vraies optimisations de gourou, et là les perfs étaient quelque chose comme 20% meilleures, quelque chose qu’ils n’ont jamais pu atteindre en scala. Par contre les optimisations en question étaient très loin d’être à la portée du dev moyen.

                            D'ailleurs, ce if, il ne sera pas optimisé par le compilateur en débogage, je me trompe? C'est peut-être une micro optim, c'est vrai, mais est-elle illisible? Et si ce n'est pas le cas, pourquoi ne pas l'utiliser?

                            Quelques raisons :
                            - la liste vide pas gérée, et c’est pas précisé (un connard va copier/coller le code et l’utiliser ailleurs)
                            - le goto est un nid à emmerdes, j’aime pouvoir faire un "grep goto *" et que ça soit vide
                            - tu optimises au mauvais endroit. Tu supprimes un test, alors que la première chose à faire, c’est d’optimiser l’allocation mémoire au moyen d’un reserve()
                            - dans le même genre, je fais mal aux mouches mais tu concatènes avec ";" alors qu’il serait plus efficace de concaténer ';'

                            Donc en gros, tu micro-optimises, mais mal, et donc tu complexifies la lecture du code pour un gain négligeable. Je préfère largement voir dans le code :

                            std::string foo = boost::algorithm::join(bar, ";");

                            qui prend une ligne à écrire, et fait ce que tu veux de manière largement assez efficace (c’est à dire, vraisemblablement autant que ta version « optimisée ») partout où ce n’est pas nécessaire de faire mieux.

                            Cela dit, si le sujet de la micro-optimisation en C++ t’intéresse, je t’invite à regarder les conf’ d’Alexandrescu, c’est hyper technique et hyper intéressant de ce point de vue.

                            Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0

                            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                              Posté par  . Évalué à 1.

                              • la liste vide pas gérée, et c’est pas précisé (un connard va copier/coller le code et l’utiliser ailleurs)
                                • tu optimises au mauvais endroit. Tu supprimes un test, alors que la première chose à faire, c’est d’optimiser l’allocation mémoire au moyen d’un reserve()

                              Ce sont des faits, mais il n'y à rien de compliqué à compléter de cette façon, comme il me semble l'avoir déjà dit. J'avais juste exprimé l'algo de façon naïve, et si j'ai pris C++ et non C, c'est parce que je n'avais pas envie de me faire chier, je l'avoue. Le but était vraiment le point unique du test préalable à la boucle, à son milieu, ou un goto.

                              dans le même genre, je fais mal aux mouches mais tu concatènes avec ";" alors qu’il serait plus efficace de concaténer ';'

                              Un point que je n'ai effectivement pas vu.

                              Je préfère largement voir dans le code : std::string foo = boost::algorithm::join(bar, ";");

                              Moi aussi, mais en fait je ne connaissais pas boost::join.

                              Cela dit, si le sujet de la micro-optimisation en C++ t’intéresse, je t’invite à regarder les conf’ d’Alexandrescu, c’est hyper technique et hyper intéressant de ce point de vue.

                              J'essaierai de me trouver ça. Ça ne peux pas faire de mal après tout.

                            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                              Posté par  . Évalué à 2.

                              J’avais lu un comparatif assez intéressant, je crois fait par les devs de scala au départ, sur les perfs entre C++, Scala, Java (je crois qu’il y avait un autre langage mais je ne me souvient plus lequel, peut-être go).

                              Je penses que tu parles de cette publication de Google.

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 4.

                Comme quoi, le goto, on le critique souvent

                En fait vu comme il est casse gueule, c'est bien de se poser la question de la pertinence de son usage quand on s'en sert.

                Pour ton problème, en java j'utilise la classe Joiner de guava. Je viens de regarder et elle fait :

                  public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
                    checkNotNull(appendable);
                    if (parts.hasNext()) {
                      appendable.append(toString(parts.next()));
                      while (parts.hasNext()) {
                        appendable.append(separator);
                        appendable.append(toString(parts.next()));
                      }
                    }
                    return appendable;
                  }

                Il y a donc une partie dupliquée (1 ligne), mais le gain en fonctionnalité est AMHA suffisant pour arrêter de se poser la question de la performance (sauf cas où tu te rend vraiment compte que ça pose problème).

                Il y a tout un tas de cas comme ça de boucles chiantes. Comme vérifier qu'un conteneur contient bien un élément donné. Soit tu te trimbale un booléen, soit tu fait un saut à l'intérieur de ta boucle, soit tu duplique ton test en sortie de boucle,…

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  . Évalué à 1.

                  Il y à la performance, et il y à la maintenance. C'est surtout le 2nd qui me pose problème: un code copié une fois, j'ai toujours peur que quelqu'un arrive, modifie un truc à un endroit et zape l'autre copie…

                  Sinon, c'est moi ou ton exemple ne gère que les string?

                  Comme vérifier qu'un conteneur contient bien un élément donné.

                  std::find, en C++. Fonctionne sur tous les conteneurs standards, du foo* au std::multi_map en passant par std::array. La STL à pas mal de ces petits algo qui sont devenus subitement utilisables depuis 2011, mais celui cité manque toujours.

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 3. Dernière modification le 19 janvier 2015 à 22:03.

                    Il y à la performance, et il y à la maintenance. C'est surtout le 2nd qui me pose problème: un code copié une fois, j'ai toujours peur que quelqu'un arrive, modifie un truc à un endroit et zape l'autre copie…

                    Ça s'utilise ainsi (tiré de la doc officielle, le code viens de ) :

                    Joiner joiner = Joiner.on("; ").skipNulls();
                    return joiner.join("Harry", null, "Ron", "Hermione");

                    Il existe des méthodes join() pour les Iterables, les tableaux et comme au dessus une variadiques. On peut aussi remplacer les valeurs null par une valeur par défaut.

                    Bref niveau ré-utilisabilité/maintenance je vois pas vraiment comment on peut faire mieux.

                    Sinon, c'est moi ou ton exemple ne gère que les string?

                    Non c'est pour ça que ça utilise la méthode toString().

                    std::find, en C++. Fonctionne sur tous les conteneurs standards, du foo* au std::multi_map en passant par std::array. La STL à pas mal de ces petits algo qui sont devenus subitement utilisables depuis 2011, mais celui cité manque toujours.

                    C'est malheureusement pas en standard en java (à moins que j'ai loupé une méthode dans l'API Stream, mais je crois pas), mais guava fais très bien les choses :)

                    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                      Posté par  . Évalué à 2.

                      C'est malheureusement pas en standard en java

                      Ta méthode pour les string n'existe pas en C++ (pas en standard en tout cas, puisque quelqu'un à pointé vers une implem boot) ;)
                      Je t'avoue que dès que je peux éviter de ramener une dépendance externe à un projet, je le fait. Pour ça que je suis très content de l'accélération qu'à prise le C++ pour ses nouvelles versions, franchement on y à gagné pas mal. Y'a plus qu'a mettre à jour les sources des softs, mais pour ça faut qu'on MaJ les cibles aussi :p
                      L'usage me paraît un peu space aussi, mais c'est normal j'imagine, je ne suis pas habitué au Java et son tout-objet (autre sujet, vaste).

                      Pour le find, j'imagine que le C++ hérite d'une plus grande habitude des classes/fonctions génériques, ça doit aider pas mal. Si je ne m'abuse, Java n'à implémenté la généricité que bien après C++.
                      Même si la STL est très pauvre comparé aux lib standard java, elle à quand même le mérite d'être puissante, et depuis 2011 d'être utilisable (un peu tard, je sais).

                      Je ne connaissais pas guava, mais à en croire wikipedia, ça à été motivé par l'introduction de la généricité dans java (2007?), du coup ça deviens logique que ça fasse bien les choses: c'est tellement moins chiant de n'implémenter qu'une fois les algo, puis de les optimiser en fonction du conteneur sous-jacent…
                      Je note, surtout qu'il y à un fort risque (c'est au niveau de la certitude en fait, sauf si je trouve un taf ailleurs) que je sois affecté à une vieille usine à gaz (intérêt technique faible, code sale --j'y ai déjà perdu un œil--, dépendance au Flex 3 et à postresql 8.X. Ça risque d'être mon rôle principal que de MaJ ce truc… snif… d'ailleurs, si quelqu'un connaît un moyen d'utiliser Flex Builder 3 aka eclipse+flash sous linux, suis preneur… je n'ose rêver d'une conversion du code en truc plus moderne permettant de se passer de flash) codée en Java.

                      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                        Posté par  . Évalué à 3.

                        Je t'avoue que dès que je peux éviter de ramener une dépendance externe à un projet, je le fait.

                        Ça se discute, mais en Java pour moi guava est une dépendance de base, je sais que je m'en sert suffisamment pour que le jeu en vaille la chandelle.

                        L'usage me paraît un peu space aussi, mais c'est normal j'imagine, je ne suis pas habitué au Java et son tout-objet (autre sujet, vaste).

                        C'est un builder, rien de spécifique à java, même si c'est peut être de plus en plus utilisé par la communauté java.

                        Pour le find, j'imagine que le C++ hérite d'une plus grande habitude des classes/fonctions génériques, ça doit aider pas mal. Si je ne m'abuse, Java n'à implémenté la généricité que bien après C++.
                        Même si la STL est très pauvre comparé aux lib standard java, elle à quand même le mérite d'être puissante, et depuis 2011 d'être utilisable (un peu tard, je sais).

                        Oui, mais ce que j'apprécie en java par rapport à la la STL, c'est l'héritage bien pensé (Collections, Iterable,…), je trouve que ça donne une API bien plus agréable à utiliser que les méthodes de la STL à base d'itérateur.

                        Je ne connaissais pas guava, mais à en croire wikipedia, ça à été motivé par l'introduction de la généricité dans java (2007?), du coup ça deviens logique que ça fasse bien les choses: c'est tellement moins chiant de n'implémenter qu'une fois les algo, puis de les optimiser en fonction du conteneur sous-jacent…

                        Et tellement pratique à réutiliser plutôt que de se réécrire l'ensemble à chaque nouveau projet avec les bugs qui vont avec.

                        Pour le reste, je ne connais rien à flex

                        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  (Mastodon) . Évalué à 7.

                mettre un if dans la boucle, et donc impact sur les performances (si c'est la boucle principale du programme, c'est dommage…),

                Ha ouais, quand même, c'est vrai qu'on va perdre en perf sur un cas aussi complexe que ça… ou pas. Qu'est-ce qui te dit que tu vas avoir un problème de perf ici ? Est-ce qu'il est plus important d'avoir un code lisible et maintenable ou un code soit-disant hyper-optimisé mais qu'il faut plus de temps à comprendre ?

                On ne le dira jamais assez : Premature optimization is the root of all evil (or at least most of it) in programming.

                Et en bonus : une implémentation de cette fonction par des gens qui connaissent un peut le C++ et bizarrement, pas de goto !

                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  . Évalué à 2.

                  Pour ceux qui aimerait avoir plus de contexte sur cette citation souvent utilisée, il y a un article intéressant à lire ici.

                  (spoiler : l'usage courant de cette citation s'approche du contre-sens de ce qu'a voulu exprimer Knuth)

                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  . Évalué à 0.

                  Moi j'ai une préférence pour DRY.
                  C'est justement un principe pour éviter les coûts de maintenance.

                  Tu dis que l'on aura peut-être pas de problème de perf sur cet endroit. Moi je te répondrai donc qu'il y en aura peut-être. Sur de petits bouts de code fréquemment utilisés, j'ai tendance à penser que je préfère connaître une version optimisée, qui n'ajoute au fond pas grand chose niveau complexité de lecture (mais la version du while est nettement supérieure, clairement) mais qui me permette de ne pas avoir à me poser la question si oui ou non c'est un endroit qui risque d'alourdir.

                  Et en bonus : une implémentation de cette fonction par des gens qui connaissent un peut le C++ et bizarrement, pas de goto !

                  C'est une raison pour laquelle j'utilise dès que je le peux les algos de la STL.

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  (Mastodon) . Évalué à 4.

                    j'ai tendance à penser que je préfère connaître une version optimisée, qui n'ajoute au fond pas grand chose niveau complexité de lecture (mais la version du while est nettement supérieure, clairement) mais qui me permette de ne pas avoir à me poser la question si oui ou non c'est un endroit qui risque d'alourdir.

                    Tu fais du travail inutile. Tant que tu n'as pas de problèmes de performances, il est inutile de vouloir les résoudre. Et utiliser un goto comme ça risque plus sûrement de te mener à un bug logique plutôt qu'à un gain en performance.

                    J'avais un étudiant une fois, un peu dans ton genre, adepte de la micro-optimisation partout. Sauf que là, il m'avait fait un algo où il insérait des éléments dans une liste triée (c'était un poil plus subtil mais ça revenait à ça). Total : complexité quadratique (en vrai, son algorithme, ça s'appelle un tri par insertion) alors qu'en insérant en vrac puis en triant derrière avec un algorithme adéquat, il avait une complexité en n log n. Pour moi, les micro-optimisations ne servent à rien, mais savoir calculer la complexité d'un algorithme et savoir utiliser les algorithmes optimaux, ça oui, ça fait gagner du temps globalement sur l'application.

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 7.

                Je viens de jouer avec gcc en -O3 et ait regardé rapidement les sorties assembleur générées par les différentes versions

                mettre un if dans la boucle, et donc impact sur les performances (si c'est la boucle principale du programme, c'est dommage…),

                Le compilo n'est pas con la sémantique des deux versions est strictement identique et l'assembleur généré avec le goto ou le if est EXACTEMENT le même.

                dupliquer la partie de code avant le label, et briser le justifié Do Not Repeat Yourself, et augmente la taille du runtime,

                DRY s'applique surtout aux concepts. Il n'y a pas grand chose de sale dans ce cas.

                Le code généré est pas identique entre les deux versions et sans microbencher très sérieusement je serais infoutu de prédire laquelle est la plus rapide. A vu de nez je me risquerait à dire que c'est identique (la seul différence est un jmp supplémentaire dans la version avec le goto). Il y a UN octet de différence de taille entre les binaires.

                C'est une vraie question: pour ce pattern la, comment faire sans goto? À efficacité maximale, j'entend.

                Tu écris le plus lisible. Le jour ou ça sortira comme un hotspot tu y réfléchiras autrement. Je prends le pari qu'on en reparle pas de si tôt vu que tu ne demandes pas un effort inhumain au compilateur pour comprendre la sémantique de ce que tu demandes…

                on peut dire la même chose des singleton

                Non le singleton n'a pas de bon usage.

                mais ce n'est pas la faute à la technique, juste à son utilisateur

                Oui surtout ceux qui veulent être très malin !

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 3.

                mettre un if dans la boucle, et donc impact sur les performances (si c'est la boucle principale du programme, c'est dommage…),

                Ça dépend de l'intelligence du compilateur et de celle du processeur. Si le compilateur n'est pas assez malin, un if qui sera vrai tout le temps sauf à la première itération donnera un branchement qui sera correctement prédit par le processeur pour N-3 itérations au moins.
                Un branchement correctement prédit peut ne coûter qu'un seul cycle.

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 2.

                Personellement, plutôt qu’un goto, je préfère le break car l’entrée dans la boucle est plus lisible :

                #include <string>
                #include <array>
                #include <cstdio>
                
                int main(void)
                {
                  std::string foo;
                  std::array<std::string, 5> bar { "azerty", "qsdfgh", "wxcvbn", "poiuyt", "mlkjhg" };
                
                  std::array<std::string, 5>::iterator foo_it=bar.begin();
                
                  // Attention la condition se trouve au milieu de la boucle.
                  for( ; ; ++foo_it )
                  {
                    foo += *foo_it;
                    if (bar.end() == foo_it)
                        break;
                    foo += ";";
                  }
                  return 0;
                }
                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  . Évalué à 3.

                  Ouai enfin si à la place j'écris quelque chose dans ce genre là :

                  for(auto foo_it=bar.begin(); bar.end() != foo_it; ++foo_it) {
                    foo += current;
                    if (bar.end() != foo_it) {
                      foo += ";";
                    }
                  }

                  Ça coute un test en plus que ta version, mais on a une boucle plus simple (on voit immédiatement qu'on itère sur l'ensemble des éléments etc).

                  Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 1.

                    Tu as raison, c’est plus clair comme ça. Je réagissais surtout au goto vers le milieu d’une boucle. Quand au test en plus, je pense que comme c’est le même que dans la condition de la boucle le programme compilé ne fera le test qu’une fois.

                  • [^] # Commentaire supprimé

                    Posté par  . Évalué à 3.

                    Ce commentaire a été supprimé par l’équipe de modération.

                    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                      Posté par  . Évalué à 6.

                      Ton code accepte des collections vides, tandis que celui d'Anthony aura un comportement indéfini (erreur de segmentation par exemple).

                      Je n'avais pas fais gaffe, mais tu as raison. C'est vraiment rigolo comme sur un algo trivial (vraiment), on voit des erreurs (ce n'est pas le premier qui a ce même problème) tout ça dans une tentative d'économiser un test ou la recopie d'une ligne de code. Le tout par des gens qui savent programmer.

                      Ça relativise un peu les failles retentissantes qui ont marquées l'année 2014 et l'intérêt de la performance à tout prix…

                      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  (site web personnel, Mastodon) . Évalué à 4.

                Sérieusement ? C'est ça ton exemple de goto incontournable ?

                #include <string>
                #include <vector>
                #include <iostream>
                
                int main(void)
                {
                    std::vector<std::string> const bar { "azerty", "qsdfgh", "wxcvbn", "poiuyt", "mlkjhg" };
                    std::string const semicolon {";"};
                
                    auto it = bar.cbegin();
                    std::string output { bar.cend() != it ?  output = *it++ : "" };
                    for( output = *it++; bar.end() != it ; ++it )
                        output += semicolon + *it;
                
                    std::cout << output << std::endl;
                
                    return 0;
                }

                En C++, goto est superfétatoire tant qu'on utilise les exceptions. Par contre, en C, l'usage de goto peut se révéler indispensable, comme le montre Linux en l'employant pour le traitement des erreurs.

                Tu remarqueras que je ne duplique pas le code : j'initialise la chaîne avec la valeur du premier élément du vecteur, s'il y en a un.

                Mais bon, la solution canonique serait plutôt d'utiliser un algorithme.

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  . Évalué à 3.

          En vrai, c'est plutôt que Ada c'est très bien sur le papier, mais que c'est un tue l'amour à réussir à passer la compilation (les inconvénients de ses avantages).

          Pourtant Rust qui intéresse beaucoup de monde est/sera ENCORE PIRE de ce côté là..

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  . Évalué à 10.

          En même temps ça m'est
          déjà arrivé de passer 1/2 journée à debugger une erreur vraiment conne en shell ou en Perl. Parfois on croit gagner du temps avec certains langages et puis en fait non.

    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

      Posté par  . Évalué à 2.

      Ben un temps j'avais bossé pour faire de la crypto sur de l'embarqué (ARM à 66Mhz…). J'étais sur un OS proprio préhistorique, mais à l'époque j'avais réussi à faire tourner une lib crypto libre XySSL, ce qui aurait été impossible si ça avait été un langage plus haut niveau. Donc aussi contre intuitif que ça puisse paraître, le C c'est aussi un gage de portabilité maximum.

    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

      Posté par  . Évalué à 2.

      Autrement on ne continuerai pas d'utiliser le C ou le C++ au lieu d'Ada (par exemple)..

      Les avantages du C et du C++ sur l'AdA sont pourtant évidents:

      • portabilité (du C ansi, je pense que ça passe juste sur 95% des µproc)
      • base de code conséquente
      • "communauté" plus vaste, donc plus simple de récupérer des contributeurs (éventuellement one-shot) ou de trouver des gens à qui demander à l'aide (petite pensée pour openmw qui à été commencé en D, puis qui est passé au C++ pour avoir plus de développeurs).

      Enfin… ADA me plaît beaucoup sur le papier. Faut juste que je me trouve le temps d'installer un compilo, de lire la doc pour trouver la commande pour générer un binaire à partir d'un source, et que je me fasse les classiques programmes de début de langage: hello world, deviner un nombre, …
      Sauf que trouver le temps pour ça, c'est pas évident, les journées sont courtes.

      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

        Posté par  (site web personnel) . Évalué à 2.

        Je pense que ne pas choisir un langage pour avoir plus de contributeur peut être un mauvais calcul. Si le dev principal passe du temps dans des problèmes à la con dû au langage (gestion de la mémoire, null pointer exception,…), il perd du temps.

        Apprendre un nouveau langage, n'est pas si difficile.

        "La première sécurité est la liberté"

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  . Évalué à 3.

          Il faudrait en parler à l'équipe d'OpenMW je pense. À l'origine le projet était codé en D, si ma mémoire est bonne.

          En tout cas, sur de petits projets que l'on peut accomplir seul ou avec peu de monde, je tendrai à être d'accord avec toi.
          Dans les autres cas non, parce que même si apprendre un nouveau langage n'est pas particulièrement problématique, il n'y à pas que le langage lui même, mais aussi les libs qu'il faut fatalement réapprendre ou l'infra à adapter (admettons qu'il y ait par exemple des outils pour analyser le code, il faut qu'ils supportent le nouveau langage ou en changer).

      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

        Posté par  (site web personnel, Mastodon) . Évalué à 2.

        la commande pour générer un binaire à partir d'un source, et que je me fasse les classiques programmes de début de langage: hello world, deviner un nombre, …

        with Ada.Text_IO;
        
        procedure Hello is
        begin
           Ada.Text_IO.Put_Line("Hello, world!");
        end Hello;

        Suivi d'un petit gnatmake hello.adb… Voilà, c'est parti, tu peux passer au deuxième chapitre :D

    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

      Posté par  (site web personnel) . Évalué à 3.

      Y'avait quel compilateur Ada accessible librement quand OpenBSD a démarré ?

      Ça ferait quelle quantité de code de reprendre tout ce qu'ils ont besoin en Ada ?

      Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

        Posté par  (site web personnel, Mastodon) . Évalué à 3.

        Y'avait quel compilateur Ada accessible librement quand OpenBSD a démarré ?

        GNAT est sorti officiellement en 95 pratiquement en même temps qu'OpenBSD.
        Le seul truc, c'est qu'OpenBSD est un fork de NetBSD qui lui-même est un fork de 386BSD.
        Inutile de dire qu'à l'époque, du code C, il y en avait déjà plein.

        Ça ferait quelle quantité de code de reprendre tout ce qu'ils ont besoin en Ada ?

        Si tu vas au bout de la démarche, il faut tout reprendre pour minimiser l'emploi du C. Au final, il ne doit te rester qu'un peu d'assembleur pour bootstrapper le tout :)
        En clair, c'est lourd mais loin d'être irréalisable.

      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

        Posté par  . Évalué à 1.

        Y'avait quel compilateur Ada accessible librement quand OpenBSD a démarré ?

        Loupé: OpenBSD date de fin 1995, la même année où il y a eu la première "validation officielle" de GNAT (dixit Wikipédia).

        Bon ceci dit, OpenBSD est un fork de NetBSD qui est bien plus vieux que ça..

        Ça ferait quelle quantité de code de reprendre tout ce qu'ils ont besoin en Ada ?

        Mais n'oublions qu'OpenBSD c'est une distribution complète, donc ils pourraient remplacer progressivement des outils userspace du C en un langage plus sécurisé (en commençant par ceux qui sont suid root), ça serait déjà un bon début..

        Pour ce qui est de la portabilité, certains langages compilent en C (par exemple Nim) donc ont -à priori- la même portabilité que le C.
        NB: Nim était juste un exemple, la version 1.0 n'est pas encore sortie!

        • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

          Posté par  . Évalué à 4.

          ils pourraient remplacer progressivement des outils userspace du C en un langage plus sécurisé (en commençant par ceux qui sont suid root), ça serait déjà un bon début..

          Ils pourraient même créer leur propre langage sans runtime, qui prend les avantages de rust/Ada etc… Bref avec des hypothèses, ont peut en imaginer des choses.

          Mais faut voir que :

          • c'est un projet qui bien que pérenne lutte un peu continuellement pour sa survie, se lancer dans ce genre de chantier qui a de bonnes chances de diviser la communauté (parler de langage à des développeurs ?) serait suicidaire
          • est-ce qu'il vaut mieux un langage moins on mais bien maitrisé ou un langage meilleur mais mieux maitrisé ?
          • L'intérêt d'Ada restera discutable, on peut probablement lancer des débats sans fin sur l'intérêt d'Ada face au C saveur OpenBSD. Grosso modo le langage ne fait pas tout et une partie de la sécurité d'OpenBSD repose sur des concepts architecturaux indépendant du langage (comme la fameuse séparation des privilèges). Si Ada garde un intérêt tout ce que je viens de citer réduit cet intérêt et le rapport coût/intérêt augmente

          Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

          • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

            Posté par  (site web personnel) . Évalué à 2.

            Pour moi, Ada, c'est dépassé. Si le but est de passé à un langage plus sécurisé, il faut regardé du coté de Haskell/Ocaml, et même Rust ou Scala.

            "La première sécurité est la liberté"

            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

              Posté par  . Évalué à 5.

              J'ai pris l'exemple d'Ada justement car c'est un vieux langage qui a un compilateur libre depuis longtemps, ce qui montre bien que la communauté libre n'est pas tellement intéressé par les langages "sécurisés".

              Note que:
              1) Haskell, Ocaml, Scala ont tous des GCs, pour certaines utilisations c'est un problème.
              2) avoir des bonnes performances avec Haskell, c'est compliqué.
              3) une JVM ça met du temps a démarrer donc Scala est a oublier pour coder des petits outils ou un démarrage rapide est nécessaire.
              4) Rust n'est même pas encore en 1.0 (seulement 1.0 alpha pour le moment).

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  (site web personnel) . Évalué à 2.

                C'est pas faux.

                Dans les domaines sensibles, la mode est aussi au générateur de code à partir de "modèle". Générateur de code écrit en Ocaml qui génère du C (Misra C en gros, sans allocation).

                Niveau sécurité maximal, je te proposerais bien SCADE, mais c'est loin d'être libre et gratuit.

                "La première sécurité est la liberté"

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  . Évalué à 4. Dernière modification le 16 janvier 2015 à 14:18.

                ont tous des GCs, pour certaines utilisations c'est un problème.

                Franchement, le problème des GCs, c'est que dès qu'il s'agit de gérer concurrentiellement autre chose que de la mémoire (fichiers, connexions base de données, sockets réseau, par exemple), on l'a où je pense, faut faire la gestion de la ressource à la main.
                Et c'est un peu la très grande majorité des programmes qui gèrent des ressources…
                C'est vraiment LA raison qui fait que j'aime tant C++, la RAII. À chaque fois que je regarde un langage qui semble sympa (le go, par exemple) je ne le retiens pas pour cette raison: devoir gérer mes ressources à la main, je ne suis pas assez bon pour ça.

                C'est aussi une raison pour laquelle ADA me fait de l'œil, et pourquoi j'ai hâte que Rust passe en bêta (oui je sais, je devrais participer pour aider si ça m'intéresse tant), parce que ça à l'air plus que prometteur: meilleure analyse du code que le C++ à la compilation, RAII, à la fois impératif et objet (ça, c'est important, ça évite de faire une immonde classe qui contienne toutes les fonctions sous forme de méthodes statiques! Java te cache pas je te vois!), généricité… faut bien l'admettre, sur le papier ça déchire.

            • [^] # Commentaire supprimé

              Posté par  . Évalué à 5.

              Ce commentaire a été supprimé par l’équipe de modération.

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  (site web personnel, Mastodon) . Évalué à 3.

                Et comme on parle de langages sécurisés, la possibilité depuis la version 2012 de placer des aspects pour définir des contrats qui peuvent lever des erreurs à l'exécution ou à la compilation.
                Bon, je vais pas répéter tout ce que j'ai déjà dit :)

              • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                Posté par  (site web personnel) . Évalué à 0.

                Un langage sans "type somme" ou ayant encore la référence "null" en 2015, c'est un peu dure.

                Pour la création de type, c'est réellement utilisable ? j'avais vu que l'on pouvait définir des ranges mais un code en réel avec des ranges mais pas de précision ne sert pas à grand chose.

                Les assert() et autre post/pre condition, c'est aussi joli que les tests unitaires. Mais quand un débordement d'entier char, te lance une exception, qui démarre un autotest dans la central inertiel de ta fusée, tu les haies tes "machins" runtime.

                En gros, si tout ses types complexe que permet de définir Ada ne fonctionne qu'au runtime, ils ne servent à rien ou presque. Ocaml a un typage complexe, et tout ou presque est vérifié à la compilation.

                "La première sécurité est la liberté"

                • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                  Posté par  (site web personnel, Mastodon) . Évalué à 3.

                  Un langage sans "type somme" ou ayant encore la référence "null" en 2015, c'est un peu dure.

                  Comme tu dis, c'est dure. Pour la référence null, je vois pas où est le problème, surtout quand on parlait de faire de la programmation système.
                  En plus, c'est pas C/C++, les pointeurs, on n'est pas obligés de s'en servir donc le null, c'est pareil, on s'en sert pas des masses.
                  Ensuite, le "type somme", je veux que tu m'expliques ce que c'est, ça me permettra de mettre à jour ma définition informatique de type.

                  Pour la création de type, c'est réellement utilisable ? j'avais vu que l'on pouvait définir des ranges mais un code en réel avec des ranges mais pas de précision ne sert pas à grand chose.

                  Ouais, t'as raison, c'est d'ailleurs pour ça qu'on peut écrire ça en Ada:

                  type Coefficient is digits 10 range -1.0 .. 1.0;

                  D'ailleurs, en point fixe aussi

                  type Volt is delta 0.125 range 0.0 .. 255.0;

                  Les assert() et autre post/pre condition, c'est aussi joli que les tests unitaires. Mais quand un débordement d'entier char, te lance une exception, qui démarre un autotest dans la central inertiel de ta fusée, tu les haies tes "machins" runtime.

                  Oh, putain !! Un bug sur de la reprise de code n'ont couvert par une vérification fait exploser UNE fusée et le langage est à jeter !! En quoi était codé Mars Climate Orbiter ?
                  Le seul truc avec Mars Climate Orbiter, c'est que ce n'était pas filmé donc l'impact sur la mémoire collective est nul.
                  D'autre part, tu reliras bien le rapport. Il n'y avait pas d'autotest du tout.
                  C'est le fait que cette centrale inertielle, liée si ma mémoire est bonne à l'axe de la fusée au décollage, soit encore en route après 30 secondes de vol qui était problématique vu qu'elle ne pouvait traiter que des accélérations dignes d'Ariane 4 donc beaucoup moins fortes qu'Ariane 5 (mais valable dans les premières secondes de vol).
                  Le bout de code n'étant pas protégé, il a renvoyé une valeur incohérente que le central n'a pu gérer. La centrale redondante ayant fait pareil, il était plus sûr, après avoir tenté de rattraper la soi-disant mauvaise trajectoire, de procéder à l'autodestruction.

                  En gros, si tout ses types complexe que permet de définir Ada ne fonctionne qu'au runtime, ils ne servent à rien ou presque. Ocaml a un typage complexe, et tout ou presque est vérifié à la compilation.

                  Ou presque… On est bien d'accord et tu montres clairement que tu ne sais pas de quoi tu parles.
                  Alors effectivement, si tu castes dans tous les sens, le compilateur va avoir du mal à te dire si tu déborderas ou pas.
                  Mais en même temps, si tu le fais, c'est justement pour dire au compilateur que tu sais ce que tu fais et qu'il ne verifiera que les nouvelles conditions.
                  Par contre, en conditions normales, il n'y a guère que les entrées externes au programme qui peuvent générer des valeurs hors plages et ça, généralement, on traite les exceptions. Alors, sauf si Ocaml a des pouvoirs de divination, je ne vois pas comment tu peux assurer que l'utilisateur ne rentrera pas n'importe quoi.

                  Bref, merci

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 2.

                    Alors, sauf si Ocaml a des pouvoirs de divination, je ne vois pas comment tu peux assurer que l'utilisateur ne rentrera pas n'importe quoi.

                    Non il te contraint à gérer les cas hors limite. Tu ne peux pas faire directement de cast, il faut dire que si la valeur est dans la plage qui convient ça roule sinon tu fait autre chose (tu met un valeur par défaut par exemple).

                    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  (site web personnel) . Évalué à 1.

                    "Ensuite, le "type somme", je veux que tu m'expliques ce que c'est, ça me permettra de mettre à jour ma définition informatique de type."

                    https://en.wikipedia.org/wiki/Tagged_union
                    https://en.wikipedia.org/wiki/Algebraic_data_type

                    C'est comme ça que tu fais un AST en 200 lignes de code, contre plusieurs dizaine de classe en langage objet classique.

                    " Un bug sur de la reprise de code n'ont couvert par une vérification fait exploser UNE fusée et le langage est à jeter !!"

                    Le principe même de planter au runtime est totalement inacceptable. Au mieux, il log un truc, mais ne plante pas ! Même facebook avec hh, log les erreurs pour éviter justement de planter leur code. On ne rajoute pas de moyen de planter dans un logiciel qui ne doit pas s’arrêter.

                    "Ou presque… On est bien d'accord et tu montres clairement que tu ne sais pas de quoi tu parles."

                    Si j'allais te parler des "case" ouvert qui n'ont pas tous les variants de définit, je pense que je t'aurais perdu en route. C'est quand même un cas très particuliers, que l'on peut éviter.

                    "Alors effectivement, si tu castes dans tous les sens, le compilateur va avoir du mal à te dire si tu déborderas ou pas."

                    Pourquoi caster ? Si tu le fait, tu pètes toutes la sémantique du machin que tu manipules et le compilo ne peut rien pour toi. Si tu es obliger de le faire, ton checker ne sert plus à grand chose, et ne te garanti plus grand chose. Mais souvent, c'est juste un problème d'architecture matériel ou limitation de langage (collection d'Object…)

                    "Par contre, en conditions normales, il n'y a guère que les entrées externes au programme qui peuvent générer des valeurs hors plages"

                    non, il suffit d'un intégrateur. Une mémoire dans une boucle. Voir une mémoire inclus dans un calcul fait à chaque pas de temps.

                    "Alors, sauf si Ocaml a des pouvoirs de divination, je ne vois pas comment tu peux assurer que l'utilisateur ne rentrera pas n'importe quoi."

                    Il exige que tu traites tous les cas, et détecte bien tous les cas.

                    "La première sécurité est la liberté"

                    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                      Posté par  . Évalué à 2.

                      C'est comme ça que tu fais un AST en 200 lignes de code, contre plusieurs dizaine de classe en langage objet classique.

                      Quoi qu'est-ce ? Ça sert à quoi ? Dans quel cadre ? (Dessert ou fromage ?)

                      "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

                    • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                      Posté par  (site web personnel, Mastodon) . Évalué à 1.

                      Le principe même de planter au runtime est totalement inacceptable. Au mieux, il log un truc, mais ne plante pas ! Même facebook avec hh, log les erreurs pour éviter justement de planter leur code. On ne rajoute pas de moyen de planter dans un logiciel qui ne doit pas s’arrêter.

                      Mais là, le langage n'a rien à voir puisque ça a planté car le code n'était pas, volontairement, protégé. En clair, les bornes des variables n'étaient pas vérifiés suite à l'introduction dans le code d'une levée des vérifications.
                      L'erreur est humaine et n'est pas à imputer au langage.

                      Si j'allais te parler des "case" ouvert qui n'ont pas tous les variants de définit, je pense que je t'aurais perdu en route. C'est quand même un cas très particuliers, que l'on peut éviter.

                      Effectivement, comme en plus en Ada, le case doit voir toutes les possibilités couvertes, j'aurais rien compris.

                      non, il suffit d'un intégrateur. Une mémoire dans une boucle. Voir une mémoire inclus dans un calcul fait à chaque pas de temps.

                      C'est quoi une mémoire dans une boucle ?

                      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                        Posté par  (site web personnel) . Évalué à 1.

                        "En clair, les bornes des variables n'étaient pas vérifiés suite à l'introduction dans le code d'une levée des vérifications."

                        Oui, mais il y a avait un comportement associé qui ne correspondait à rien de voulu. Le langage peut aider quand le comportement doit être explicite, cela permet de voir un défaut de couverture par les tests par exemple. Au minimum, cela permet de mettre un mode dégradé en place.

                        "Effectivement, comme en plus en Ada, le case doit voir toutes les possibilités couvertes, j'aurais rien compris."

                        Le principe des variants est justement que tu ne les définit pas tous, à l'inverse des types sommes…

                        "C'est quoi une mémoire dans une boucle ?"

                        une variable modifiable. Une boucle-for explicite est facile à lire et facile de voir le problème, c'est beaucoup moins le cas d'intégrateur temporel (genre correcteur pid).

                        "La première sécurité est la liberté"

                • [^] # Commentaire supprimé

                  Posté par  . Évalué à 3.

                  Ce commentaire a été supprimé par l’équipe de modération.

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  . Évalué à 0.

                    On peut générer du code qui va effectivement vérifier tout ça à l'exécution, ou on peut s'en passer. C'est au choix.

                    La solution la plus sûr c'est d'obliger le développeur à écrire ce code et à ne pas le générer ni à rester sans.

                    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                    • [^] # Commentaire supprimé

                      Posté par  . Évalué à 4.

                      Ce commentaire a été supprimé par l’équipe de modération.

                      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                        Posté par  (site web personnel) . Évalué à 2.

                        "Non. La méthode la plus sur, c'est de prouver formellement du code (méthode B par exemple). "

                        Pour être dans le milieu, ce n'est pas le cas. La méthode B est surtout utilisé dans le ferroviaire. Le "milieu" croit surtout au norme (do178,iso26262,en50128, IEC61508…).

                        " Exemple ? Les try/catch foireux en java à cause de l'obligation de gérer les exceptions (i.e., le catch est vide, mais c'est nécessaire pour que cela compile)."

                        C'est pas faux, les normes imposent bien plus de chose.

                        "Sans oublier l'impact que cela peut avoir sur la taille du binaire et les performances (dans des environnements comme l'embarqué, ces "détails" peuvent être importants)"

                        On n'utilise pas Java dans l'embarqué critique. La JVM est loin d'être qualifiable/certifiable. Et l'usage du GC rend cela encore plus complexe.

                        "La première sécurité est la liberté"

                      • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                        Posté par  . Évalué à 2.

                        Obliger le développeur, c'est le meilleur moins d'obtenir, pardonne moi l'expression, de la merde. Exemple ? Les try/catch foireux en java à cause de l'obligation de gérer les exceptions (i.e., le catch est vide, mais c'est nécessaire pour que cela compile).

                        Bon exemple, l'obligation du try/catch ça rend la merde de tes développeurs visible.

                        D'après toi qu'est-ce qui est mieux entre :

                        int value = (int) anotherValue;

                        et

                        int value;
                        try {
                           value = anotherValue.atoi()
                        } catch(...) {
                        }

                        Le second montre clairement que tu as un cas d'erreur possible (que tu le traite ou non), il t'oblige à donner un valeur par défait (si tu utilise value sans l'initialiser dans la plupart des langages ton compilateur va hurler).

                        Tu ne pourra jamais empêcher un développeur qui fait n'importe quoi à faire n'importe quoi. La preuve de programme n'empêche pas celui qui l'a fait de faire n'importe quoi.

                        Ce qui est reprochable à des langages comme java c'est de ne pas être suffisamment expressif pour gérer tout ça de manière réellement agréable (entre autre via le patern matching, la capacité à produire du code exception free et la capacité du langage à exprimer tes contraintes dans des types -là dessus ada est pas mal-).

                        Au passage, ta preuve de programme va simplement t'obliger à écrire ce code de gestion d'erreur, peut être moins car tu exprime mieux les contraintes de tes données (tu sais que ta méthode n'est jamais utilisé qu'avec en entrée des valeurs paires).

                        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                        • [^] # Commentaire supprimé

                          Posté par  . Évalué à 0.

                          Ce commentaire a été supprimé par l’équipe de modération.

                          • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                            Posté par  . Évalué à 3.

                            Non justement j'ai bien choisi de ne pas lui donner de type. Disons que c'est un foo si ça t'arrange et prenons le C++ comme ça tu peut avoir dans ta classe foo (si c'est une classe) avoir défini comment convertir un foo en int.

                            Pour moi, ça montre surtout que la lecture d'un code (pour sa relecture par exemple) est très compliquée, qu'il faut avoir pleins de choses en tête, donc un langage qui va être capable de mettre en évidence les erreurs potentielles dans sa syntaxe est bénéfique (tu as moins de risque d'avoir des oublis, tu as moins de choses à penser en même temps donc tu peux plus te concentrer sur la valeur ajouter de ton programme,…).

                            Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                            • [^] # Commentaire supprimé

                              Posté par  . Évalué à 1.

                              Ce commentaire a été supprimé par l’équipe de modération.

                            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                              Posté par  . Évalué à 5.

                              En C++ on aurait pas utilisé de cast C-style.

                              On peut, c'est vrai, mais c'est parce que ce langage ambitionnes d'être compatible avec le C.
                              Moi, je vois un cast C-style en C++, je me dis "Hé merde… ça, ça pue". Si je vois un static_cast, je suis plutôt confiant, un dynamic_cast, je vérifie si il y à une gestion des exceptions ou de pointeur null, et reinterpret_cast, je relis le code à plusieurs reprises, mais au moins je sais que c'est dangereux.
                              Contrairement au cast C-style, ou je me dis que ça pue parce que ça peut être l'équivalent de n'importe quel autre cast.

                              Finalement, plus le temps passe, plus j'ai l'impression que le plus gros défaut de C++ est sa compatibilité avec le C… mais c'est aussi ce qui fait qu'on peut utiliser sans prise de tête des libs codées en C, à la qualité aléatoire.

                  • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

                    Posté par  (site web personnel) . Évalué à 1.

                    "Pour le type somme, tu veux parler de l'union en C "

                    Cela y ressemble de loin. cf les liens au dessus.

                    "D'abord, c'est sur que faire passer le débordement sous le tapis en l'ignorant et en espérant que tout passe, c'est bien mieux"

                    Il faut se rattraper aux branches. Sortir avec une exception est juste inacceptable.

                    "On peut générer du code qui va effectivement vérifier tout ça à l'exécution, ou on peut s'en passer. "

                    Oui, on peut, mais donc cela ne t'aide pas tant que ça.

                    "Essai d'assigner 99 à une variable ne pouvant contenir qu'un entier entre 1 et 50 et tu verras."

                    a = 99; mais a = 40+40; ? et a +=1; ?

                    "La première sécurité est la liberté"

            • [^] # Re: Pas sûr que trouver des erreurs/la fiabilité soit si important pour la communauté libre..

              Posté par  (site web personnel, Mastodon) . Évalué à 3.

              Ben, moi, si j'avais vraiment besoin de sécuriser, je ferai du Spark :)
              Comme quoi, les goûts et les couleurs…

  • # efficacité des différentes méthodes de tests

    Posté par  . Évalué à 2.

    c'est un article intéressant, et en particulier le diagramme mais qui me fait me poser des questions sur cette corrélation entre la méthode pour détecter les bugs et son efficacité

    en effet, d'après ce diagramme, la méthode qui donne le meilleur résultats serait d'avoir un béta test à grande échelle, et à l'inverse, une autre qui donne des résultats médiocre concerne les tests de non régression

    la question que je me pose est la suivante :
    est-ce que le fait que chacune de ces 2 méthodes donne des résultats totalement opposés (autour de 80% pour la première et proche de 25% pour la seconde) ne serait pas dû au moment du projet ?

    je m'explique : le béta testing va être fait tout au début d'un projet (dans sa version initiale) au moment où justement il y a de très nombreux bugs, alors que les tests de non régression seront mis en œuvre que bien plus tard, lorsque le projet a qques années derrière lui et que l'on veut lui apporter une certaine "patine"

    l'exemple typique que j'ai en tête pour ces tests de non régression est le projet SQLite :
    https://www.sqlite.org/testing.html
    et c'est justement incroyable de voir à quel point le ration nombre de lignes de code du logiciel / nombre de lignes de code pour les tests est bas (1017 fois plus de lignes de code pour les tests que pour SQLite !!)
    néanmoins, il n'est pas dit que ça a permis de trouver un grand nombre de défauts

    en conclusion, je me demande si l'efficacité de ces méthodes n'est pas plutôt dépendante du moment où elle sont effectuées plutôt que de la méthode elle-même

    • [^] # Re: efficacité des différentes méthodes de tests

      Posté par  . Évalué à 4.

      Des tests de non-régression, par définition, ne permettent pas de trouver des défauts (sous entendu "nouveaux") mais de s'assurer qu'ils ne reviennent pas.

      C'est ce qu'oublient souvent les gens quand ils critiquent les tests (unitaires, de non-régression, etc.). Dans l'expression assurance qualité, le terme assurance est important : grâce aux tests, on sait que certains bugs n'existent pas. Sans les tests, on peut croiser les doigts et compter sur la méticulosité des développeurs, mais en réalité on ne sait jamais à coup sûr ce qui marche et ce qui ne marche pas. Surtout que sauf exception on a très peu de testeurs des versions alpha et béta, donc la plupart des bugs sont rapportés après une sortie officielle.

      en conclusion, je me demande si l'efficacité de ces méthodes n'est pas plutôt dépendante du moment où elle sont effectuées plutôt que de la méthode elle-même

      Je dirais plutôt que c'est le soin avec lequel elles sont appliquées. Par exemple, des tests peuvent aller du trivial (tester un cas nominal et basta) jusqu'au très poussé (lancer des tas de threads et pousser une API dans ses derniers retranchements, simuler des erreurs d'allocation mémoire, etc.).

    • [^] # Re: efficacité des différentes méthodes de tests

      Posté par  (site web personnel) . Évalué à 1.

      La relecture de code permet de trouver des erreurs qui peuvent être très compliqué à testé.

      Les tests finaux (intégration) permet de trouver les erreurs qui seront trouvé en 1er par l'utilisateur, or c'est le plus important.

      Les outils statiques ont le bonheur de fonctionner sur tout le code, cela permet d'avoir beaucoup de garanti (typage fort, absence de valeur null…)

      "La première sécurité est la liberté"

  • # Une autre approche est possible

    Posté par  (site web personnel) . Évalué à 9. Dernière modification le 14 janvier 2015 à 23:22.

    L'erreur est humaine et les tests unitaires ne sont (presque) jamais exhaustifs, il existe fort heureusement d'autres approches.

    LA PREUVE DE PROGRAMME !

    Il est sans doute intéressant de rappeler comment le gars qui a trouvé la faille SSL a procédé :
    Le gars a utilisé Coq un puissant assistant de preuve (mathématiques) pour "révéler" le bug.
    La méthode qu'il a employée est tout simplement fantastique : http://ccsinjection.lepidum.co.jp/blog/2014-06-05/CCS-Injection-en/index.html#how-did-i-discover-the-bug
    Clairement c'est le genre de gars qui ouvre la voie pour démocratiser la démonstration de programme.
    Pour ceux que çà intéresse un cours bien fait sur le sujet (orienté Coq) : http://fuscia.inrialpes.fr/cours/coq/

    Bien sûr il est irréaliste de vouloir développer un programme d'envergure en Coq mais ces techniques commence à être disponibles sur des langages "mainstream".
    Leon (http://lara.epfl.ch/w/leon) par exemple est très prometteur pour démontrer du code en Scala.

    Mais il existe tout un tas d'outils et d'approches pour vérifier/démontrer qu'un programme est correct : https://github.com/johnyf/tool_lists/blob/master/verification_synthesis.md

    IMHO c'est çà l'avenir de l'informatique et c'est par ce biais que ce fera la jonction (naturelle) avec les mathématiques !

    Tous les développeurs devraient s'intéresser à la preuve de programme et pas seulement les universitaires ou les boites spécialisées.

    • [^] # Re: Une autre approche est possible

      Posté par  (site web personnel) . Évalué à 8.

      D'ailleurs, on vient tout juste de brancher la version 8.5 de Coq, et avec la quantité de récompenses reçues par Coq l'année dernière, je pense que c'est l'occase pour une petite dépêche pour sensibiliser les moules à la volaille !

      • [^] # Re: Une autre approche est possible

        Posté par  . Évalué à 4. Dernière modification le 26 janvier 2015 à 18:22.

        Bien sûr il est irréaliste de vouloir développer un programme d'envergure en Coq mais ces techniques commence à être disponibles sur des langages "mainstream".

        Laborieux, certes, irréaliste pas sûr… Connais tu compcert ?
        C'est un compilateur C écrit en Coq dont chaque représentation interne est formellement spécifiée et chaque transformation est formellement prouvée en Coq (notamment les optimisations qu'il applique).

        edit : je voulais répondre à newca, pardon…

    • [^] # Re: Une autre approche est possible

      Posté par  . Évalué à 2.

      J'ajouterais à tous tes liens un excellent cours (en anglais), très pédagogique, sur à la fois le formalisme et la preuve de programme, le tout très orienté (et écrit en) Coq, et que je recommande souvent, l'excellent Software Foundations de Benjamin C. Pierce.

  • # les tests qui marchent pour de vrai

    Posté par  (site web personnel) . Évalué à 3. Dernière modification le 15 janvier 2015 à 10:11.

    C'est pas mal comme liste. Mais quand on a un budget limité et que l'on ne peut pas tout faire, il faut rechercher le plus efficace.

    Les teste unitaires complet sont très contraignant, et peu utile. Par contre, les tests lié à un bug, qui doit de tout façon, doit être écrit pour le corriger, est utile pour éviter son retour.

    Un truc qui est généralement interdit est de générer une sortie, vaguement vérifié puis d'utiliser des diffs. Cela ne permet pas de savoir si le code est correcte, cela permet de savoir si quelques choses à changer. En général, ce genre de test est simple à mettre en œuvre mais nécessite que le codeur sache que ce qu'il fait, que sa modification change la sortie de façon volontaire ou non. C'est plus un détecteur de changement, qu'un test.

    Le test a ne pas oublier, et qui est indispensable, est le test de plus haut niveau : celui de l'utilisateur. En effet, beaucoup de bugs "unitaires" peuvent être masqué et n’impactent pas l’utilisateur final.

    Dans le cas d'une GUI, il y a peu de chance que ses tests soient automatisables, et si ils le sont, la maintenance peut être prohibitif. Par contre, ce sont les tests qui ont le plus de valeur, car les client verront la même chose.

    Ensuite, pour les programmes complexes, plutôt que des tests unitaires qui testeront finalement très peu les combinaisons des exigences, je préfère le fuzzing. Il s'agit de générer rapidement et aléatoirement des entrées plus ou moins fausse pour tester les réactions du programme. La condition de sorti est en général, simple : ne pas planter. Parfois, il est possible de faire plus compliquer. Un compilateur peut se faire injecter des programmes aléatoires, puis compiler le résultat avec et sans optimisation, l’exécution des 2 programmes doit avoir le même comportement.

    "La première sécurité est la liberté"

    • [^] # Re: les tests qui marchent pour de vrai

      Posté par  . Évalué à 3.

      Tu aurais des infos sur l'application de fuzzing, dans la pratique? Je vois bien comment ça marche en théorie, mais dans la pratique, je ne vois pas trop comment le mettre en place. Tu écris un programme dédié pour tester la cible?

      • [^] # Re: les tests qui marchent pour de vrai

        Posté par  (site web personnel) . Évalué à 2.

        https://pypi.python.org/pypi/fusil a été développé par un lecteur de linuxfr.

        J'imagine qu'il doit être possible de faire un générateur générique de fichier XML à partir d'une DTD.

        Sinon, oui, c'est du custom, surtout pour générer un ensemble d'entré valide.

        "La première sécurité est la liberté"

      • [^] # Re: les tests qui marchent pour de vrai

        Posté par  . Évalué à 0.

        Il y a plein de frameworks dispo genre Peach ou Sulley ou autre qui te permettent de modeler le format de tes données, voir donner des exemples de données, et ces frameworks te génereront des données malformées mais proches du format réel.

        Ensuite certains comme Peach ont aussi une infrastructure pour lancer ton soft, lui faire passer les données malformées et regarder si le soft crashe, si il crashe il logge ce qui s'est passé, etc… et te fait un joli rapport au final.

  • # Pas con

    Posté par  . Évalué à 10.

    L: Béta test à faible volume (moins de 10 sites)
    M: Béta test à haut volume (plus de 1000 sites)

    Je vais demander une rallonge à l'ESA pour qu'on envoie 1000 satellites en bêta avant de lancer le satellite de production.

    Tous les nombres premiers sont impairs, sauf un. Tous les nombres premiers sont impairs, sauf deux.

Suivre le flux des commentaires

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