Journal Moi, expert C++, j'abandonne le C++

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
86
3
juin
2019
Ce journal a été promu en dépêche : Moi, expert C++, j’abandonne le C++.

Sommaire

Je profite de cette anecdote pour rédiger un long journal afin de partager mon expérience et mon apprentissage en espérant t’apprendre de nouveaux points de vue.

Peut-être cela vaut le coup d'en faire une dépêche… Dis-le moi dans les commentaires. 😉

Ma passion C++11, C++14, C++17…

Ma carrière professionnelle de développeur C a débuté en 1994 et j’ai naturellement adopté avec enthousiasme le C++ en 1999.
J’étais un développeur C++ heureux et j'avais considéré la nouvelle version du standard C++11 juste comme une évolution tant attendue.

Mais en 2015, je réalise enfin à quel point C++11 a révolutionné l’écosystème C++ et ses bouleversements dans l’état d’esprit de la communauté C++.
Je me passionne alors pour C++11, C++14 puis C++17, je m’implique beaucoup, je deviens un référent pour mes collègues, je donne des conférences sur le C++, j’organise des Meetups à Paris, je publie de nombreux articles C++ sur LinuxFr.org…

Comprendre le client et développer vite

Cependant, en 2018, une expérience change radicalement ma façon d’appréhender le développement logiciel.
À cette époque, une équipe C++ se retrouve surchargée et ne peut implémenter toutes les fonctionnalités attendues.
On réfléchit à une solution de secours, et me voilà chargé de développer une application en Python en intégrant des briques sous licence libre.
Je travaille alors en étroite collaboration avec les utilisateurs finaux et on sort l’application en quelques mois.

Ma nouvelle vision :

Il y a plus important que la technologie,
c’est de se mettre dans la peau du client final
et de comprendre ses frustrations au quotidien.
Et on y arrive mieux en intégrant l’utilisateur final
dans son équipe de développement.

L’application bricolée en Python donne entièrement satisfaction.
Les utilisateurs sont contents d’avoir eu très tôt leur outil, et cela a coûté moins cher par rapport à toute une équipe C++ dans sa tour d’ivoire.

Intégrer l’utilisateur final dans son équipe

Attention, je ne dénigre pas le C++, celui-ci peut être une bonne solution face à de nombreuses problématiques.
Mais avant de courir tête baissée, s’assurer que la technologie choisie répondra bien aux attentes non exprimées de l’utilisateur final.
J’écris « attentes non exprimées" car bien souvent le développeur se base sur sa propre interprétation
d’un document présenté comme LA spécification qui a en plus été rédigée par un intermédiaire (MOA, MOE, Business Analyste, Product Owner, Architecte…)

Nous l’avons peut-être déjà tous constaté, l’utilisateur final ne sait pas vraiment ce qu’il veut, et a beaucoup de difficulté à exprimer clairement par écrit ses attentes.
Un intermédiaire (MOA, MOE, BA, PO, Archi) est nécessaire pour lui permettre de prendre du recul
et pour traduire une demande fonctionnelle en exigence technique.

Mais l’intermédiaire rajoute une couche intermédiaire !
C’est humain, l’intermédiaire aura tendance à se rendre indispensable.
Et sans le faire exprès, l’intermédiaire évitera que développeurs et utilisateurs échangent en direct.

Le top est d’avoir l’utilisateur final dans son équipe de développement, même si ce n’est pas dans le même bureau. Avec les habitudes de travail à distance, développeurs et utilisateur peuvent clavarder (chat) régulièrement.

Faire des sprints d’une journée

La durée idéale d’un sprint c’est la journée.
Le matin on échange rapidement avec le client de ce que l’on pourrait faire, on s’attelle à la tâche, on livre, l’utilisateur peut tester, on re-livre…
Et, en fin de journée, on débriefe très rapidement.

L’intérêt du Python (par rapport au C++) dans ce mode de fonctionnement c’est la livraison :
on peut se permettre de livrer directement le code source et hop l’utilisateur exécute l’application !
Ainsi, dans mon cas, quand l’utilisateur lançait le démarrage de l’application, la branche master du dépôt Git était automatiquement mise à jour.
J’essayais quand même de le prévenir quand une nouvelle version était sur la branche master.

La joie de livrer souvent, rapidement, et d’avoir du feed-back dans la foulée :-)

Le C++ ne serait donc pas la panacée ?

Nous pourrions caricaturer :

  • En C++, le développement est lent, mais l’application est très rapide ;
  • En Python, le développement est rapide, mais l’application est très lente. ¹

¹ Utiliser Pythran/PyPy/Cython/Numba/… accélère l’exécution, mais cela ralentit le développement : compilation plus lente, développement plus complexe, bug difficile à investiguer…

Bien souvent, le client final a besoin rapidement d’une fonctionnalité, même si l'exécution n'est pas super optimisée.
En livrant rapidement cette fonctionnalité, le client gagne en maturité et a de nouvelles idées, de nouvelles façons pour optimiser son travail… et ainsi de suite avec des itérations courtes.

WebSocket en Python

Pour une application existante, nous avons besoin de fournir une interface WebSocket basique afin que nos clients puissent accéder à un service de Souscription/Publication.

Je développe la fonctionnalité en utilisant Python et Socket.io.
Les tests JavaScript sont concluants.
Cependant, nous nous apercevons que Socket.io rajoute son protocole par-dessus le protocole WebSocket.
Nous allons donc forcer les clients à devoir utiliser Socket.io ce qui n’est pas acceptable.

Nous voulons offrir une simple WebSocket afin que le client ne soit pas enfermé dans une technologie et soit libre d’implémenter son logiciel comme il le souhaite.

Je m’oriente alors vers WAMP avec Autobahn…
Mais rebelote le P dans WAMP signifie Protocol.

Pour ne pas réinventer la roue, je cherche alors une solution qui implémente déjà la fonctionnalité Souscription/Publication et idéalement avec des coroutines (async et await).

WebSocket en C++

C’est alors que je découvre uWebSockets (µWS), une implémentation C++17 à couper le souffle qui intègre la fonctionnalité Souscription/Publication tout en conservant le protocole WebSocket de base. \o/

Mon équipe est enthousiaste. Je clone le projet, j’adapte un exemple C++ à nos besoins et je présente un résultat convainquant. C’est agréable de compiler un projet C++ qui ne tire pas des dizaines de dépendances :-)

Je précise que pour ce nouveau projet, je viens de rejoindre une autre organisation, et j’ai été embauché, en partie, pour mes connaissances pointues en C++17.

Benchmark fait par l’équipe uWebSockets qui montre que uWebSockets est largement la solution la plus performante

La compilation C++ est archaïque

En Python, Node.js, Ruby, Go, Rust on a pip, npm, gem, go-get, cargo qui simplifie le téléchargement des dépendances, et l’intégration au projet avec un import xxxx. De plus, certains IDE prennent en charge cette gestion des dépendances.

En C++, la gestion des dépendances et leur compilation ne sont pas standardisées. En fait, cela n’a pas beaucoup évolué depuis les origines : le C++ a 40 ans et se compile toujours dans le même esprit que le C qui a lui 60 ans.

Pour cela, nous avons le choix du compilateur, dont voici une sélection avec leurs dates de naissance :

  • GCC et son g++ (GNU, libre, 1987-2019)
  • LLVM et son clang++ (Apple, libre, 2007-2019)
  • AOCC et son clang++ (AMD, libre, 2017-2018)
  • ICC et son icc (Intel, non-libre, ????-2018)
  • MSVC et son cl (Microsoft, non-libre, 1993-2019)
  • C++Builder et son bcc64 (Embarcadero, non-libre, 1997-2019)

Construction logicielle C++

Pour la construction logicielle (build), nous avons une dizaine d’outils pour nous abstraire du compilateur, en voici une petite sélection sous licence libre :

  • make et son Makefile
  • Ninja et son build.ninja
  • Jam remplacé par Boost.build et leur Jamfile
  • SCons et sa configuration en Python
  • Waf qui ambitionne de remplacer SCons

Générateurs de configuration pour la construction logicielle C++

Et pour nous abstraire de ces outils de construction logicielle, nous utilisons des générateurs de configuration de build, dont voici des projets toujours actifs :

  • Autotools génère du Makefile
  • CMake génère Makefile, build.ninja et les fichiers projet pour de nombreux IDE
  • Premake en cours de réécriture active depuis une dizaine d’années
  • xmake génère Makefile et les fichiers projet pour quelques IDE
  • Meson génère build.ninja et est compatible avec quelques IDE

Autres outils de construction logicielle C++

Avec les outils ci-dessus, le build et les tests de non régression d’une importante application C++ peut parfois prendre une demi-journée.
C’est beaucoup trop pour attendre si ce que l’on a implémenté est correct !

D’autres outils de construction logicielle ont donc été développées dans le but de builder/tester en un minimum de temps :

  • Bazel codé en Java et géré/financé par Google
  • Buck codé en Java et géré/financé par Facebook
  • Pants codé en Python et géré par une communauté
  • Please codé en Go et géré/financé par Thought Machine

Ces projets ne réutilisent pas les outils de build cités plus haut, et ne génèrent pas les fichiers projet des IDE.

Par contre, ces outils analysent finement le graphe de dépendance, gèrent de gros dépôts de code source,
parallélisent la construction logicielle sur tous les cœurs (CPU) de nombreuses machines (cloud).
Les étapes du build sont mémoïsées pour éviter de refaire la même opération N fois (par exemple, pour éviter de compiler un fichier non modifié, ou de linker une bibliothèque inchangée).

Sans avoir à recourir à ces outils, on peut améliorer les temps de compilation C++ et d’édition de liens (link) avec ces deux bons vieux outils :

  • ccache pour éviter de recompiler (ou linker) un fichier inchangé
  • distcc pour distribuer le build sur plusieurs machines (voir aussi icecream)

Ces outils ccache et distcc sont pris en charge par CMake, SCons…

Gestion de dépendances en C++

Mais au fait, comment gérer les dépendances C++ ?
Quel est le gestionnaire de paquets C++ officiel ? (package manager)
Quel est l’équivalent C++ pour les commandes pip, npm, gem, go-get et cargo ?

Eh bien… disons que nous avons des initiatives encourageantes :

  • Le groupe de travail SG15 (du comité de standardisation du C++) réfléchit à une nouvelle approche pour compiler le C++ (voir leurs propositions P1482 et P1484 en anglais) ;
  • Le projet build2 est très bien pensé et dont son auteur avait proposé de standardiser arborescence des projets C++ avec P1204 ;
  • Le projet conan utilise une configuration en Python et propose déjà 600 paquets C++ disponibles sur les deux dépôts publics principaux (conan-central et bincrafters)
  • Le projet vcpkg se base sur CMake et propose 1000 paquets C++ dont une bonne partie sont compatibles Windows, GNU/Linux et macOS
  • Le projet Hunter se base également sur CMake et propose environ 300 paquets C++

Attention à ne pas confondre l’exécutable b du projet build2 avec l’exécutable b2 du projet Boost.build cité plus haut.

Copier les dépendances dans son code source

Une autre façon de gérer très simplement ses dépendances C++ est de carrément copier le code source de celles-ci (et aussi le code source des dépendances des dépendances) avec le code source de l’application. Ça compile toujours.

Mais ce n’est pas une bonne pratique pour, au moins, deux raisons :

  • Respecter les licences libres, c’est avant tout éviter de mélanger des codes sources de licences et d’auteurs différents
  • Mixer les codes source complique leur mise à jour (par exemple, comment intégrer la correction d’une faille de sécurité ?)

Microsoft me fait perdre deux jours

Je teste différents moyens pour obtenir le paquet uWebSocket : le package manager de ma distribution, Conan, Hunter… et finalement, le paquet uWebSocket a fraîchement été intégré au dépôt vcpkg. Je teste, et, au miracle, cela télécharge le code source et me l’installe sur ma distribution GNU/Linux !

L’outil vcpkg fonctionne avec CMake, donc ce sera CMake qui gérera la construction logicielle.
Le temps de se documenter et bien prendre en main vcpkg, de tenter une intégration dans mon CMakeLists.txt, d’échouer, de recommencer…

Pourtant l’exemple avec SQLite3 fonctionne chez moi… Arg… En fait, c’est mal empaqueté, le find_package() ne pourra jamais trouver la bibliothèque uWebSocket fournie par vcpkg.

J’essaye de le faire moi-même. Puis, je me rends compte au second jour que vcpkg est un outil amateur, a ne surtout pas utiliser pour aller en production : pas de version des dépendances, impossible de décider des options de compilation des dépendances…

Allez, on empaquette soi-même cette bibliothèque

Bon, je connais bien C++, alors empaqueter proprement une bibliothèque qui ne dépend de rien ne devrait pas poser problème.

Je retrousse mes manches et je commence à chercher si quelqu’un a déjà empaqueté uWebSockets…

Je trouve surtout que le mainteneur principal a supprimé les fichiers CMakeLists.txt et meson.build en 2017.
Et celui-ci semble envoyer bouler les contributeurs proposant la compatibilité avec CMake, supprime le titre des Pull Request et on trouve même des commentaires supprimés.

On trouve une explication dans la FAQ :

I don't accept any specific build systems because I know from experience that doing so opens up hell. People simply cannot agree on which build system to use, or even how to use one particular build system.

That's why I no longer accept any such PRs. I've had too many CMake PRs dragging in completely different directions to know this is the only solution.

You'll have to clone the repo and create a new project in whatever build system you want to use.

En gros, le mainteneur principal refuse tout système de construction logicielle, car les développeurs veulent utiliser différents outils et que pour un même outil, les développeurs ne se mettent pas d’accord de la bonne façon de faire.

Un commit très étonnant est le Not my problem qui change la licence et remplace dans tous les fichiers la ligne :
Copyright 2018 Alex Hultman and contributors.
par:
Authored by Alex Hultman, 2018-2019.
Intellectual property of third-party.

CMake gagne, Meson rentre à la maison

Mon IDE préféré pour le C++ est QtCreator, mais celui-ci ne prend pas encore en charge Meson. Et je n’ai plus beaucoup de temps pour prendre en main GNOME Builder.

Et j’obtiens un joli CMakeLists.txt qui fonctionne sur deux différentes distributions GNU/Linux et aussi sur GitLab.

Je me rends aussi compte que GCC-8 ne compile pas cette bibliothèque, et que nous devons utiliser seulement Clang.

Mais, mon plus gros problème est que je n’arrive plus à faire compiler cette bibliothèque par QtCreator, alors qu’avec la ligne de commande cela fonctionne parfaiement… Arg… J’investigue encore du temps…

Échec C++

Mes collègues ne comprennent pas pourquoi je mets autant de temps pour faire l’équivalent d’un pip install en C++. De plus, je vais devoir refaire ce même travail dès que j’intégrerai les autres bibliothèques : base de donnée, file d’attente de message, journalisation

Nous décidons ensemble d’arrêter de s’obstiner, de relever la tête, et de lister les possibilités :

  • Continuer l’intégration de uWebSockets avec CMake
  • Utiliser seulement les paquets Conan ou Hunter comme boost::beast pour la websocket (c’est même disponible avec apt install)
  • Revenir sur le Python et implémenter la Souscription/Publication
  • Passer sur Node.js et intégrer la bibliothèque C++ uWebSockets avec la simplicité de npm (uWebSockets.js)
  • Prendre le virage Rust, seul rival au C++ avec la simplicité de cargo
  • Go to the langage Go qui est simple comme Python et est une des technos les plus performantes

WebSocket en Node.js

J’ai plusieurs collègues très compétents en Node.js, alors c’est parti. Effectivement, l’installation de la dépendance est très simple et on implémente rapidement l’application.

Le grand avantage de Node.js (et de JavaScript en général) est la taille de la communauté et l’esprit de partage et d’innovation incroyables. Alors qu’il est nécessaire d’une décénie en C++ pour se décider, la communauté JavaScript décide en quelques mois. Les projets, les concepts de programmation, les méthodes de travailler ne cessent d’évoluer.

J’entre dans un vaisseau qui se déplace à la vitesse de la lumière. En C++, la durée de vie d’un projet peut être d’une dizaine d’années. En Node.js, c’est plutôt 10 mois. C’est aussi l’inconvénient, il faut s’adapter vite.

Mais, nous nous apercevons que le projet uWebSockets.js ne prend pas en charge la Souscription/Publication de la bibliothèque sous-jacente uWebSockets. Ça ne marche pas.

Stop, nous venons de gagner en maturité, voyons voir les possibilités :

  • Node.js (implémenter la Souscription/Publication en JavaScript…)
  • Rust
  • Go

WebSocket en Go

Nous prennons concience que la partie WebSocket risque d’être un point sensible au niveau performance. Finalement, nous mettons entre parenthèses notre tentative Node.js.

Le Rust est encore trop jeune (peu de développeurs maîtrisant Rust sur le marché). Et nous avons un collègue devops fan du Go.

Notre collègue maîtrisant Go n’étant pas très disponible, on apprend se débrouille seul. Finalement, le principal du langage Go s’acquiert en quelques heures de programmation. Le test WebSocket est un succès et nous implémentons une première version basique de la Publication/souscription en Go.

Nous mettrons en place des tests de performance reproductibles, et seulement après nous pourrons décider quelles sont les parties qui nécessitent d’être optimisées.

Valoriser l'échec

  • C'est grâce à nos échecs successifs que nous avons pu trouver notre solution pour les WebSockets
  • Nous aurions pu décider qu'il fallait éviter les échecs
  • Mais nous avons plutôt chercher à se planter car l’échec est un très bon moyen d’apprendre (de ses erreurs)
  • Se planter plus rapidement/souvent permet donc d’apprendre plus vite/souvent
  • Donc, essayons d'augmenter nos échecs (car c'est augmenter notre apprentissage)
  • Pour encourager à tester une idée, nous devons valoriser l'échec
  • Tester simplement/rapidement une idée permet de gagner en maturité

Enseignements sur les langages

  • Ce n’est pas une bonne idée de coder dans son langage de programmation (C++) quand on est le seul dév. de l’organisation qui connaisse ce langage
  • JavaScript et Node.js ça décoiffe
  • Go c’est vraiment simple (car c’est limité)

Louanges sur la simplicité

  • La simplicité permet de se concentrer sur l’essentiel
  • Faire simple est souvent compliqué
  • Avoir une IT simple permet d’intégrer de nouvelles contraintes/idées plus facilement
  • Dans un monde de plus en plus concurrentiel et qui s’accélère, la simplicité évite de se perdre dans le brouillard

Je continue d’aimer le C++

Mais, non, je n’abandonne pas le C++ !

J’apprécie d’acquérir de nouvelles cordes à mon arc,
de m’ouvrir l’esprit sur de nouvelles pratiques.

Certaines technologies sont plus adaptées à certains contextes.
N’ayons pas de dogme, choisissons la bonne techno selon la situation.

Cependant, je ne sais pas quand je coderai à nouveau en C++…
Peut-être quand on aura un C++ package manager standardisé… :-)

On embauche

Un peu de publicité : Tu apprécies cet état d’esprit et que tu aimes coder en Python, Node.js, JavaScript/TypeScript/Angular ou Go ? N’hésite pas à me contacter sur oli (à) Lmap (point) org. Nous avons des postes à Paris et à Metz. On peut s’arranger pour le télétravail. Pour le moment, on ne publie rien sous licence libre. Mais je pousse pour libérer quelques briques intéressantes…

  • # Et par rapport au C ?

    Posté par  . Évalué à 8.

    N'étant que développeur amateur et ayant appris et déjà programmé en C, je vois défiler ici une quantité de journaux sur le C++. J'ai eu tenté d'apprendre le C++ mais j'ai très vite déchanté devant sa complexité. Quelqu'un pourrait-il m'expliquer les différences entre C et C++ qui justifieraient de passer au C++ ?

    • [^] # Re: Et par rapport au C ?

      Posté par  . Évalué à 3.

      Entre autres :

      • le besoin de dév à l'aide d'un langage orienté objet
      • la contrainte, si tu te retrouves obligé d'utiliser un framework (parait qu'on dit "cadriciel", beurk …) en C++

      Je suis certain qu'on pourrait allonger la liste. Mais devant mon p'tit déj, je ne vois que ça !

    • [^] # Re: Et par rapport au C ?

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

      À vue d'œil:

      • Plus de facilité pour faire de l'orienté-objet ;
      • Pas mal d'outils supplémentaires pour éviter de faire des boulettes (RIAA, smart_ptr<>, etc) ;
      • Pas mal d'outils supplémentaires pour pouvoir faire des boulettes (bizarreries sur certains trucs genre unique_ptr<>, etc) ;
      • Quelques outils pour faire moins de code et/ou plus optimisé (exceptions, etc) ;
      • Quelques outils pour faire plus de code (templates de templates de templates, etc).

      (PS: J'ai 10 ans de C derrière moi, mais clairement pas autant en C++)

    • [^] # Re: Et par rapport au C ?

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

      Passer à C++ serait pour utiliser Qt ? Cela serait ma principal motivation. La deuxième serait un besoin énorme de performance et devoir jouer avec le SIMD, les directive OpenMP, gérer finement la mémoire( même si Rust fait mieux).

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

    • [^] # Re: Et par rapport au C ?

      Posté par  . Évalué à 9.

      Certains te l'ont déjà évoqué mais la principale motivation pour passer au C++ est le support du paradigme objet.

      De base le C n'est qu'un langage procédural. Lorsque tu programmes dans certains domaines l'approche objet est assez "naturelle".
      Même si c'est théoriquement possible avec le C tu te retrouves très vite limité par le langage. Si tu es intéressé cet ouvrage est fait pour toi: https://www.cs.rit.edu/~ats/books/ooc.pdf)

      Simuler un héritage rudimentaire et le polymorphisme à base de "cast" est à peu près tout ce que tu peux atteindre, simplement.

      Au delà tu réinventes tellement de truc qu'il vaut mieux se poser la question de savoir s'il ne faut pas passer à autre chose. C'est la vocation de C++ et d'ObjectiveC

      Avec le C++ tu auras automatiquement:
      * la redéfinition des méthodes, statiques ou virtuelles (bon courage avec les pointeurs de fonction dans tes structures en C)
      * l'héritage multiple
      * La généricité qui te permet d'instancier de nouveaux types abstraits
      * la surcharge des opérateurs ainsi que de nouveaux (>>)

      Il y aussi tous les frameworks autours qui peuvent te faciliter la vie (ramasse-miette, …)

      Tu as une belle base de comparaison aujourd'hui avec les 2 toolkits graphiques mainstream sur Linux: GTK ecrit en C prouve que c'est possible. Qt a fait le choix de s'appuyer sur le C++ et déborde largement le cadre de l'interface graphique aujourd'hui.

      C'est donc à toi d'évaluer ton besoin sachant que ça peut-être superflu. Par exemple le multi-héritage a aussi ses inconvénients et on peut s'en passer simplement avec la notion d'interfaces. Java est là pour en attester. (Et je n'aborde pas les design pattern, composition vs héritage, …)
      De même l'approche objet ne résout pas tout. Aujourd'hui, le paradigme fonctionnel revient en force et on s'appuie aussi beaucoup sur la programmation par aspect pour compléter l'approche objet de manière orthogonale (Spring AOP en java, …).

      En revanche si tu n'appréhendes pas la programmation objet et que tu veux comprendre, je ne suis pas certain que le C++ soit le langage le plus adapté étant donné sa complexité. GTK est peut-être un 1er point d'entrée pour ça.

      Mais il vaut peut-être mieux aussi commencer par des langages plus simple et plus productifs (l'auteur m'en est témoin) comme le Ruby (pur objet) et le python (qui prend quelques libertés avec le duck typing par exemple) et qui offrent en plus l'avantage d'être multi-paradigme et moins contraignants au début de par leur typage dynamique .

      A partir de là, peut-être que l'abord du C++ sera moins rugueux.

    • [^] # Re: Et par rapport au C ?

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

      j'ai très vite déchanté devant sa complexité

      Le C++ est peut être plus complexe, mais il n'est pas plus compliqué que le C.
      Par exemple, le Brainfuck est extrêmement simple (seulement 8 instruction à apprendre en 2 minutes), mais il est en fait très compliqué de faire des programmes avec.
      Le C++ demande peut être un peu plus d'apprentissage, mais permet de faire des programmes plus facilement qu'en C.

      • [^] # Re: Et par rapport au C ?

        Posté par  . Évalué à 4.

        Je me souviens de mon partiel de C++ à la fac il y a >15ans et notamment d'un délicieux exercice sur les supplices syntaxiques du langage.

        Je me dis que C++ a du être une belle source d'inspiration pour Brainfuck ;-)

        BeOS le faisait il y a 20 ans !

        • [^] # Re: Et par rapport au C ?

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

          Il me semble que tu n'as pas compris ce que je voulais dire alors je vais essayer de mieux expliquer.

          Brainfuck justement à une syntaxe très simple et très facile à apprendre. Chacune des huit instructions s'explique en une phrase. Après deux minute tu es un expert dans le langage. Un expert ? Pas vraiment, car la difficulté du langage n'est pas dans la syntaxe, mais dans son utilisation.

          C++ a peux être une syntaxe qui prends un chouia plus de temps à apprendre, mais, en pratique, est plus facile d'utilisation que le brainfuck, et que le C, pour faire des programmes.

          Quand à ton partiel à la fac, n'importe quel professeur peux te faire des délicieux exercices sur la syntaxe de n'importe quel langage s'il le veux. Chaque langage à ses coins difficiles et ses subtilités. Mais il n'est pas non plus nécessaire de connaître touts les recoins les plus reculés d'un langage pour pouvoir écrire et lire des programmes en pratique.

      • [^] # Re: Et par rapport au C ?

        Posté par  . Évalué à 9.

        Par exemple, le Brainfuck est extrêmement simple (seulement 8 instruction à apprendre en 2 minutes), mais il est en fait très compliqué de faire des programmes avec.

        Ce n'est pas si compliqué, sa notoriété est galvaudée. C'est juste une syntaxe embêtante. Malbolge est vraiment complexe.

  • # L'herbe est toujours plus verte dans le pré du voisin

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

    Le C++ ne serait donc pas la panacée ?

    bah… Pas toujours en effet, mais bon à chaque fois que j'ai eu à me taper un autre langage au bout d'un moment j'en ai vu des limites, des galères (entre autre les perfs!), des incompatibilités dans le temps (le passage de Python 2 à 3 a été quand même bien laborieux), des changements de mode etc… Au final avec mon code C++ j'ai quand même l'impression que je peux l'adapter à de nouvelles plate-formes plus facilement, le code traverse le temps plus facilement, après faut avoir besoin de ce "fonctionnalité".

    Bref, effectivement il y a des trucs gavant en C++ mais l'herbe est toujours plus verte dans le pré du voisin (tant qu'on n'y a pas goutté donc), c'est surtout une question de goût des membres de l'équipe plutôt que de choix rationnels.

    Peut-être quand on aura un C++ package manager standardisé… :-)

    Si déjà on pouvait commencer par des repos Linux standardisés… Ha ben non, ça vit et personne n'arrive à se mettre d'accord, on a toujours rpm vs deb vs arch vs etc! Bref, ce n'est pas unique à C++ (mais oui, ça me gonfle ce manque).

    On peut s’arranger pour le télétravail.

    Ca, c'est un bon point! Dommage que tu ne cherches pas de dev C++, j'aurai peut-être postulé ;-).

  • # Oui, mais non

    Posté par  . Évalué à 10.

    Bon, déjà, je code en C++ si je veux ! Même si je suis le seul de la boite à connaître ce langage ! Normal, on est 2 dév, et l'autre est spécialisé application mobile, et donc Java, Objective C, et maintenant, Kotlin et Swift.

    Joli post, bien mieux structuré et écrit que je n'aurais pu le faire sur cette longueur !

    ("mais ?…")
    Mais !

    T'inquiètes, aucune attaque frontale, voire aucune attaque. Quelques remarques.
    Ça dépend !

    Trois grands points :

    1. le contexte : quand la cible est un micro-contrôleur (MCU), c'est généralement C, point barre. L'exception arrive avec les MCU puissants, avec écran : souvent, le framework de gestion de l'IHM est en C++

    2. la méthode (et le contexte) : tu décris la méthode agile, mais elle ne peut pas s'appliquer partout. Déjà, j'imagine que Airbus, Bombardier, Arcelor et plein d'autre regarder ça avec encore beaucoup de méfiance. Ensuite, ça se passe bien de ton côté, mais dans ma boite, quelle fumisterie ! On a "fait de l'agile" parce que c'était à la mode ! Mis à part l'absence de maîtrise par le management, mon ressenti est que ce n'est pas applicable à mon métier ou à mon niveau. En effet, une carte sur un Trello n'a jamais constitué une spécification pour moi. A la limite, si le manager/client avait su étoffer ces cartes … Mais comme les gens qui ont déjà vu de vraies specs et des vrais chef de projet se compte sur les doigts d'une main dans la boite … Sur 800 personnes quand même, hein !

    3. le framework : je ne prétends pas tout connaître, loin de là, ni forcément connaître le meilleur. Mais ça me surprend, on dirait que tu est passé à côté de Qt. J'en suis tombé amoureux en 2003 chez Bombardier, pour faire de l'IHM dans des trains. Qt, c'est plein de choses :

    • première coup d'oeil : ça sert à faire des IHM. Oui mais.
    • ça couvre plein de domaines différents : réseau, XML, multithreading … La liste est longue comme un discourt de Ma€ron !
    • c'est multi plateforme : pour la partie C++, forcément, il faut recompiler. Mais ça tourne déjà sous Windows, macOS et Linux (KDE est basé dessus par exemple). C'est également le premier choix pour faire une IHM (ou une appli sans IHM aussi, pourquoi pas) dans l'embarqué sous Linux, avec Yocto ou Buildroot. Mais pas seulement, point suivant :
    • depuis quelques années, une nouvelle façon de faire les IHM est apparue : QML/QtQuick. Séparation de la partie fonctionnelle en C++ de la partie IHM en QML, langage de script, et déclaration/description de l'IHM, saupoudré de JavaScript quand ça suffit. En parallèle, chez Qt, ils ont ajouté iOS et Android comme cible. J'arrête ici, je suis moins familier avec cette partie de Qt
    • j'oublie très certainement plein de chose, allez voir leur site !

    Accessoirement, même quand un projet n'est pas sous Qt, je m'arrange pour utiliser QtCreator, l'IDE du framework. Un IDE fait par des dév, pour des dév. Direct à l'essentiel : le code !

    Disclaimer : aucun ! Non, je ne bosse pas pour Qt !

    • [^] # Re: Oui, mais non

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

      Vu comme tu décris ton expérience avec Agile, je pense que ça s'est passé pour toi de la même manière que pour moi dans ma boîte précédente. Un dinosaure de l'informatique (ta boîte pas toi) voit la mode de l'Agile et se dit "tout le monde fait ça, il faut faire pareil". Alors ils collent le mot Agile sur tout et n'importe quoi.

      Si le client n'est pas impliqué dans le projet, si il ne teste pas régulièrement (je dirais 1 fois par semaine au moins) les délivrables pour faire des retours et changer l'orientation de l'équipe, ce n'est pas de l'Agile et il y'a peu de chances qu'il en ressorte quoi que ce soit de positif.

      • [^] # Re: Oui, mais non

        Posté par  . Évalué à 5.

        Un dinosaure de l'informatique (ta boîte pas toi) voit la mode de l'Agile et se dit "tout le monde fait ça, il faut faire pareil". Alors ils collent le mot Agile sur tout et n'importe quoi.

        A mon avis c'est comme ça pour plus de la moitié des boites qui disent être agiles : pour elles lorsqu'elles ontpassé le délai de mise à disposition d'une nouvelle appli de 6 mois à 4 mis, elles peuvent se prétendre agile.

    • [^] # Re: Oui, mais non

      Posté par  . Évalué à 3.

      la méthode (et le contexte) : tu décris la méthode agile, mais elle ne peut pas s'appliquer partout. Déjà, j'imagine que Airbus, Bombardier, Arcelor et plein d'autre regarder ça avec encore beaucoup de méfiance. Ensuite, ça se passe bien de ton côté, mais dans ma boite, quelle fumisterie ! On a "fait de l'agile" parce que c'était à la mode ! Mis à part l'absence de maîtrise par le management, mon ressenti est que ce n'est pas applicable à mon métier ou à mon niveau. En effet, une carte sur un Trello n'a jamais constitué une spécification pour moi. A la limite, si le manager/client avait su étoffer ces cartes … Mais comme les gens qui ont déjà vu de vraies specs et des vrais chef de projet se compte sur les doigts d'une main dans la boite … Sur 800 personnes quand même, hein !

      C'est surtout une agilité mal maîtrisée, il me semble. L'idée principal de l'agilité c'est d'avoir une boucle de rétroaction sur la façon de travailler d'une équipe. Pour ça, une façon de faire (celle de scrum) est de mettre en place des segments courts (les sprints) que l'on évalue via les rétrospectives. Mais ce n'est pas la seule façon.

      Se concentrer sur les outils (trello, des post-it, jira, whatever) ce n'est pas agile du tout :)

      En effet, une carte sur un Trello n'a jamais constitué une spécification pour moi. A la limite, si le manager/client avait su étoffer ces cartes … Mais comme les gens qui ont déjà vu de vraies specs et des vrais chef de projet se compte sur les doigts d'une main dans la boite … Sur 800 personnes quand même, hein !

      Donc vous n'avez pas de documentation, ok. Ça ce n'est pas la faute de l'agilité, comment vous faites pour vous en sortir sans ? L'agilité peut justement donner des clef sur comment se débrouiller sans documentation (la mise en place de démo pour échanger sur une fonctionnalité, d'autres types de réunions comme l'eventstorm peuvent aussi aider).

      Mon point ce n'est pas qu'il faut forcément faire de l'agile, juste reprendre ton point pour donner des pistes sur comment ça aurait pu mieux se passer pour vous.

      • [^] # Re: Oui, mais non

        Posté par  . Évalué à 6.

        Donc vous n'avez pas de documentation, ok. Ça ce n'est pas la faute de l'agilité, comment vous faites pour vous en sortir sans ?

        Pas.

        Bon, ce serait un peu long à expliquer, mais disons que sur les 800 personnes, une partie est à l'IT, le reste, c'est essentiellement du commerce. Chez ce gros "retailler" comme ils disent, notre équipe de R&D est constituée de … 3 personnes : un ingé électronicien, un ingé dév mobile et IoT, et moi, pour l'embarqué.
        Donc non, on a pas de doc, ou alors on la fait nous même. Quasiment personne d'autre que nous dans la boite n'a vu des spécs dans sa vie, encore moins rédigé.
        On a fait à 100% (design, électronique, soft) deux produits en 2015 : succès technique, échec commercial pour plusieurs raisons, trop long à détailler.
        Depuis, on fait du proto, avec la méthode "Quick & Dirty" …
        Protos qui n'ont donné aucun produit jusqu'à présent, vu que le commerce a une vision à court terme et n'est toujours pas capable de trouver les volumes de vente suffisant pour rentabiliser la R&D, le design, etc.
        La majorité des produits vendus en magasin consistent en du sourcing (marque blanche, surtout en provenance de Chine) avec tests/validation réglementaire en labo, retouche design, un peu de custom …

        Euh, faut que j'arrête de me répandre ici, on va finir par me reconnaître ! Et puis on est pas chez le psy …

        • [^] # Re: Oui, mais non

          Posté par  . Évalué à 4. Dernière modification le 03 juin 2019 à 10:33.

          Donc vous n'avez pas de documentation, ok. Ça ce n'est pas la faute de l'agilité, comment vous faites pour vous en sortir sans ?

          Pas.

          Tu dis « l'agilité ça ne marche pas chez nous à cause de la doc », c'est qu'il y a bien un moment où quelque chose à fonctionné. Sinon tu n'a aucune idée de si c'est l'agilité qui n'a pas fonctionné ou juste vous qui êtes une équipe de shadoks (rien de personnel).

          Si rien n'a jamais fonctionné, alors oui c'est qu'on vous a vendu l'agilité comme une solution miracle et que vous y avez cru.

        • [^] # Re: Oui, mais non

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

          L'agilité sans "le client", dans la boucle, n'est pas de l'agilité.

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

          • [^] # Re: Oui, mais non

            Posté par  . Évalué à 9.

            Et un manager ne peut pas remplacer le client…

            • [^] # Re: Oui, mais non

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

              Le manager ne respecte en général jamais sa part de contrat dans l'agilité : le contenu d'un sprint est décidé au début de celui-ci.

              Si cela casse, tout ce qui est rythmé par le sprint casse (genre l'équipe de teste qui valide le sprint précédent, va se tourner les pouces)

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

      • [^] # Re: Oui, mais non

        Posté par  . Évalué à 10.

        Je vais profiter de ton commentaire pour rebondir sur celui-ci quelques autres ainsi que sur une remarque de l'auteur :)

        donner des clef sur comment se débrouiller sans documentation

        Même si tu donnes quelques éléments pour étayer, on peut pas laisser passer çà :)

        L'agilité n'a jamais prétendu qu'il fallait se "passer" de la documentation, bien au contraire.
        Le principe, comme pour le reste, est de faire ce qui est suffisant au bon moment çar le changement peut, enfin non, va, arriver. Tout comme on n'se fait pas plaisir avec une archi géniale qui servira jamais (overdesign) et qu'on fait "juste ce qu'il faut".

        En effet, une carte sur un Trello n'a jamais constitué une spécification pour moi. A la limite, si le manager/client avait su étoffer ces cartes

        Voilà, ca tombe bien, pour l'agilité non plus. Si tu as des contraintes réglementaires, on ne va pas te dissuader d'en faire.
        Une US c'est juste morceau de fonctionnalité dont on peut mesurer la valeur ajoutée et qu'on peut livrer à temps pour plaire à celui qui paye, le métier. Point barre
        Qu'on en fasse une unité de tâche n'empêche pas qu'on puisse la découper en sous-tâches ou même qu'on la retravaille.
        https://www.youtube.com/watch?v=rP9AlpFwvSM

        A mon avis c'est comme ça pour plus de la moitié des boites qui disent être agiles : pour elles lorsqu'elles ontpassé le délai de mise à disposition d'une nouvelle appli de 6 mois à 4 mis, elles peuvent se prétendre agile.

        Petit "test":
        - On est super agile, on a des sprints de 2 semaines
        - Vous avez des tests ?
        - Bin non tu rigoles avec le pressing de l'AMO , on n'a pas le temps
        - J'ai une bonne nouvelle comme vous êtes agile, on va se lancer dans un petit refactoring des familles, parce que là ça pue le syndrome du copier-coller
        - OMG!

        Nous l’avons peut-être déjà tous constaté, l’utilisateur final ne sait pas vraiment ce qu’il veut, et a beaucoup de difficulté à exprimer clairement par écrit ses attentes.
        Un intermédiaire (MOA, MOE, BA, PO, Archi) est nécessaire pour lui permettre de prendre du recul
        et pour traduire une demande fonctionnelle en exigence technique.
        Mais l’intermédiaire rajoute une couche intermédiaire !
        C’est humain, l’intermédiaire aura tendance à se rendre indispensable.

        Allez, on reprend les bases: le manoifesto
        Working software withoutover comprehensive documentation
        Customer collaboration over contract negotiation

        Voilà, on privilégie ce qui marche plutôt que la paperasse inutile: un doc de spec de 500 pages que l'AMO n'ose pas tamponner de peur de s'être planté ou à balancer parce que le business a déjà changé. Un modèle UML aux petits oignons que le métier pige pas et qui sera complètement obsolète au moment de la livraison.

        Si documentation il y a, il faut qu'elle reflète l'état du projet à l'instant t, bref qu'elle soit "vivante" ET qu'elle serve. Quoi de mieux qu'un exemple élaboré avec toutes les parties prenantes pour être sûr qu'on a tous pigé le même truc sans "intermédiaire". S'autoriser à challenger le PO sur cette base pour être sûr qu'il sait ce qu'il veut ou lui montrer que ça tient pas debout.

        Allez un petit rituel pour bien s'accorder sur les règles métier avant de valider que la US est "Ready" et s'assurer qu'on va pas (moins) se planter sur le planning (la "cistomer collaboration"):
        https://www.youtube.com/watch?v=gID0boETxJQ
        https://cucumber.io/blog/example-mapping-introduction/

        Le PO/AMO est pas jouasse ? Et bin on se protège:
        https://www.youtube.com/watch?v=C9XoZQdnKbA&list=PLxTb_ZC4kmrSBKSyz3N4rtYjdE7EaI0Uu

        Et comment qu'on fait pour s'assurer que ces règles sont bien respectées ?
        Et bin on les teste (non la vocation du BDD Bevaviour Driven Design n'est pas le test mais bien piger ce que veut le client), on les rend "executables". La voilà la living documentation:
        https://www.youtube.com/watch?v=p1Tl8kfkjGM

        Et ca veut pas dire qu'il faut "tout" tester en Cucumber et écrire des tests d'IHM en Ghekin, hein

        Allez, on pousse encore un peu le truc avec l'archi. Un peu de sketch modeling pour le début du sprint (ton exemple est quand même très orienté EDA ca correspond pas à tout les projets)

        Et puis pour le newbie, quoi de mieux que de lire les TUs pour se mettre dans le code ? En voilà une autre de belle "living documentation" à base d'exemples pour peu qu'on soigne un peu le présentation (Clean code, domain driven). Oui on soigne ses tests et on les refactore avec le même soin que le code.
        https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882

        Le "Done Done", c'est pas pour la déco, …

        Voilà le truc, c'est de faire du bottom-up et plus du top-down (on oublie le MDA)

        Ca tombe bien, un petit français nous a fait un super talk dessus:
        https://www.youtube.com/watch?v=Tw-wcps7WqU&list=PLTbQvx84FrAS5clN9i8_LFUQxcMY7qXAO&index=118

        et a même pondu un bouquin au financement libre:
        https://leanpub.com/livingdocumentation
        A consommer sans modération, avec par exemple comment rétrogénerer de la doc d'archi avec un bon framework des famille et quelques annotations, DDD, Documenation by convention, …
        Une mine d'or.

        Alors c'est sûr la 1ere fois si on fait l'impasse sur tout ça, l'AMO, le PO, il s'habitue: "Vous avez pulsé , les gars!" et on ne pourra pas revenir dessus. Les bugs tombent, la dette technique s'accumule on fait l'impasse sur la doc en crachant sur la méthode et l'agilité Ultime et Universelle se met en place aka:
        http://www.la-rache.com/

        • [^] # Re: Oui, mais non

          Posté par  . Évalué à 2.

          donner des clef sur comment se débrouiller sans documentation

          Même si tu donnes quelques éléments pour étayer, on peut pas laisser passer çà :)

          L'agilité n'a jamais prétendu qu'il fallait se "passer" de la documentation, bien au contraire.
          Le principe, comme pour le reste, est de faire ce qui est suffisant au bon moment çar le changement peut, enfin non, va, arriver. Tout comme on n'se fait pas plaisir avec une archi géniale qui servira jamais (overdesign) et qu'on fait "juste ce qu'il faut".

          Mon point n'était pas qu'il ne faut pas de doc, mais que des approches agiles donnent des approches différentes de la documentation et justement les 2 points que j'ai donné servent à produire de la documentation.

          • [^] # Re: Oui, mais non

            Posté par  . Évalué à 4.

            Je l'ai bien saisi. J'ai d'ailleurs mis un bémol. Juste que la formulation était ambigüe et l'idée reprise par d'autres.
            Accessoirement, c'était aussi un prétexte pour placer ma tirade ;-)

    • [^] # Re: Oui, mais non

      Posté par  . Évalué à 2.

      Bon, déjà, je code en C++ si je veux ! Même si je suis le seul de la boite à connaître ce langage ! Normal, on est 2 dév, et l'autre est spécialisé application mobile, et donc Java, Objective C, et maintenant, Kotlin et Swift.

      Et le jour ou il faut partager une lib entre Kotlin et Swift le plus simple sera… de la faire en C++ ! Ben oui, aujourd'hui ton code va se promener sous Android, iOS, Node etc. Et si à peu près tous les langages """modernes""" permettent d'appeler une fonction dans une lib native d'une façon ou d'une autre (Java JNI, Node N-API…) les interfacer entre-eux reste beaucoup plus difficile.

  • # CI/CD

    Posté par  . Évalué à 10. Dernière modification le 03 juin 2019 à 08:55.

    Faire des sprints d’une journée

    Tu devrais pouvoir faire la même chose facilement en C++ avec une solution de CI/CD type gitlab-ci/drone/sourcehut : il suffit d’automatiser la compilation d’un .exe et sa publication au push sur master.

  • # Performance

    Posté par  . Évalué à 10.

    • En C++, le développement est lent, mais l’application est très rapide ;
    • En Python, le développement est rapide, mais l’application est très lente. ¹

    ¹ Utiliser Pythran/PyPy/Cython/Numba/… accélère l’exécution, mais cela ralentit le développement : compilation plus lente, développement plus complexe, bug difficile à investiguer…

    Je sais que c'est une caricature, mais une démarche en python est un peu différente. Elle dit que la majeure partie de ton application n'a pas besoin d'une performance importante. Donc coder la partie qui demande une grosse performance en c/c++/go/rust/julia et l'interfacer1 avec le reste de ton application en python peut être pertinent. Ça permet en plus d'avoir de coder la partie métier dans un langage de très haut niveau et la partie technique dans un langage qui permet d'accéder au très bas niveau.


    1. pas forcément dans un wrapper python comme vous utilisez des broker de messages ça peut passer par là 

    • [^] # Re: Performance

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 04 juin 2019 à 08:16.

      Je sais que c'est une caricature, mais une démarche en python est un peu différente. Elle dit que la majeure partie de ton application n'a pas besoin d'une performance importante. Donc coder la partie qui demande une grosse performance en c/c++/go/rust/julia et l'interfacer1 avec le reste de ton application en python peut être pertinent. Ça permet en plus d'avoir de coder la partie métier dans un langage de très haut niveau et la partie technique dans un langage qui permet d'accéder au très bas niveau.

      Exactement. Python et C++ ne joue pas dans la même court.

      • Python est fait pour faire du prototypage rapide avec du code qui finira difficilement maintenable due à son typage dynamique et ses performances.
      • C++ est fait pour du code système avec des code base où la performance compte et des projets qui peuvent tourner 30 ans et toujours faire le boulot et être maintenu (déja vu).

      D'ailleurs ironiquement python et ses modules sont principalement fait en C et C++ (CPython, Cython, numpy, tensorflow, SSL layer, pycurl, ….). Le restant étant un joli layer de scripts au dessus

      • [^] # Re: Performance

        Posté par  . Évalué à 2. Dernière modification le 04 juin 2019 à 08:53.

        • Python est fait pour faire du prototypage rapide avec du code qui finira difficilement maintenable due à son typage dynamique et ses performances.
        • C++ est fait pour du code système avec des code base où la performance compte et des projets qui peuvent tourner 30 ans et toujours faire le boulot et être maintenu (déja vu).

        Je ne suis pas d'accord avec ça :

        • ton application C++ en 30ans tu l'a réécrite 2 fois au moins (une fois pour prendre en compte C++98 et une pour C++11) si tu t'en es bien sorti. Oui tu as aussi dû réécrire ton application python pour passer à python3 on est d'accord. C'est juste pour dire que la maintenance de ce genre de code même en C++ ce n'est pas trivial du tout.
        • la performance de python n'est pas aussi pathologique que ce que tu avance. C'est du code compilé, il n'est pas aussi véloce que d'autres, mais on est pas dans l'univers PHP5
        • son typage dynamique par rapport au typage statique du C++ est contrebalancé par 2 choses :
          • il est beaucoup plus simple d'écrire des tests, mais vraiment beaucoup. Le duck typing (ou le typage structurel) est un bonheur pour ça
          • il existe un outillage autour de python beaucoup plus riche que pour C++. Par exemple pour reprendre mon premier point, tu es beaucoup plus aidé pour passer de python2 à python3 que pour passer mettre à jour ta base de code C++ vers le nouveau standard. Oui en python c'est bloquant et en C++ c'est rétrocompatible, mais on voit dans les commentaires que les développeurs C++ sont bien moins indulgents que les compilateurs C++.
        • [^] # Re: Performance

          Posté par  . Évalué à 4.

          ton application C++ en 30ans tu l'a réécrite 2 fois au moins (une fois pour prendre en compte C++98 et une pour C++11) si tu t'en es bien sorti. Oui tu as aussi dû réécrire ton application python pour passer à python3 on est d'accord. C'est juste pour dire que la maintenance de ce genre de code même en C++ ce n'est pas trivial du tout.

          If it works, don't fix it !!!

          Le code entre C++ 98 (ou 2003), est compatible avec le C++11, mise à part quelques cas marginaux comme des using namespace std et using boost::shared_ptr, pas besoin de mettre à jour le code. Lors de modifications de code (évolution), il est tout à fait possible de faire la mise à jour du code dans le cadre de l'évolution.

          il est beaucoup plus simple d'écrire des tests, mais vraiment beaucoup.

          il y a pas mal de composant de test (cppunit, google test suit) qui rendent l'écriture de test très aisée.

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Performance

            Posté par  . Évalué à 6. Dernière modification le 04 juin 2019 à 09:19.

            If it works, don't fix it !!!

            On voit ici des gens qui n'ont pas du tout envie de bosser sur ta vielle base de code.

            il y a pas mal de composant de test (cppunit, google test suit) qui rendent l'écriture de test très aisée.

            On ne parle pas des même magnitude. Je viens du monde Java du test on en a plus que ce que peut imaginer en C++ (une bibliothèque de test qui fait référence avec un format qui fait standard de fait dans le reporting de tests, des bibliothèques d'assertion et de mock on en a pleins), mais le typage de java (ou du C++) rendent l'écriture de test bien moins pratique qu'en python/go. En java on a la chance d'avoir un runtime extrêmement flexible ce qui permet d'avoir spock, mais il faut remercier groovy et sa compatibilité avec java.

            • [^] # Re: Performance

              Posté par  . Évalué à 8.

              If it works, don't fix it !!!

              On voit ici des gens qui n'ont pas du tout envie de bosser sur ta vielle base de code.

              Moi je vois des managers, des chef de département qui n’ont pas 100k€ à dépenser pour une mise à jour de code qui :

              • Fonctionne en l’état ;
              • Est toujours conforme à la norme ;
              • Va ajouter des tests, de l’intégration ;
              • Un client qui ne veut que des évolutions, il ne paye pas un nouveau dev. ;
              • Des équipes en places à reformer ;

              Lorsqu’il y a une bonne base de code qui marche, de bibliothèque qui fonctionne, pourquoi prendre le risque de tout changer ?

              • [^] # Re: Performance

                Posté par  . Évalué à 6. Dernière modification le 04 juin 2019 à 09:51.

                Je comprends ton point, je dis juste qu'il te suffit de regarder plus haut ou plus bas pourvoir un certains nombre d'exemples de développeurs qui n'ont pas envie de toucher à cette base de code. Ils sont prêt à changer de boulot plutôt que d'y toucher. Le manager fait bien ce qu'il veut de son coté. Je ne parle que de ce que je vois.

                Après il y a un tas de raisons à mettre à jour sa base de code :

                • c'est une dette technique que tu accumule et que tu va probablement devoir payer un jour
                • un code pas touché pendant un certain nombre d'années devient très difficile à maintenir (quelque soit le langage)
              • [^] # Re: Performance

                Posté par  . Évalué à 5.

                Ben juste parce que le mec qui a fait ça avant il est mauvais. Le nouveau développeur qui a réussi son stage de fn d'année réussira mieux que le dino qui a écrit tout ça avant lui. LEs nouveautés du langage lui permettront de simplifier et de mieux faire marcher le code.

                Cette mode de réparer ce qui marche, surtout dans le monde du libre me gave depuis des années. Je me dis parfois que le code payant a du bon : au moins on réinvente pas la roue tous les 6 mois parce qu'un pneu est dégonflé.

                • [^] # Re: Performance

                  Posté par  . Évalué à 9.

                  Ben juste parce que le mec qui a fait ça avant il est mauvais.

                  Je ne suis pas d’accord, le truc écrit dans les années 90 (pour des vieilles bases de code) on été écrite avec des contraintes de l’époque. L’ancien dev. n’est pas nécessairement plus mauvais.

                  Le nouveau développeur qui a réussi son stage de fn d'année réussira mieux que le dino qui a écrit tout ça avant lui.

                  Je vois plutôt l’inverse, les jeunes qui sortent de l’école ne savent utiliser que des IDE qui font tout à leur place, si la fonction n’existe pas, oups ! Le jeune va te refaire tout un super design car le langage permet plein de nouveau truc. Sauf que par manque d’expérience, il va se prendre les pieds dans le tapis de cas tordu : « Ah bon, ça peut arriver ? ».

                  Je fais passer des entretiens techniques dans ma société pour des embauches, j’ai eu mon premier candidat qui a su me dire que le c++ avait des normes, il a même réussi à me les nommer… mais pas à me dire, même vaguement, ce qu’elles apportent.

                  Je crois qu’ici on est dans un petit monde clos avec un niveau technique supérieur à la moyenne… ça fausse le débat.

                  • [^] # Re: Performance

                    Posté par  . Évalué à 5.

                    je ne suis pas d'accord […]

                    je pense l'inverse […]

                    je pense que si vous êtes d'accord, tu as juste loupé le deuxième degré de totof2000, il me semble.

                    • [^] # Re: Performance

                      Posté par  . Évalué à 3.

                      je pense que si vous êtes d'accord, tu as juste loupé le deuxième degré de totof2000, il me semble.

                      Je suis parfait, je ne peux rien rater ! 😇 même si je pense que tu as raison…

                    • [^] # Re: Performance

                      Posté par  . Évalué à 3.

                      Il te semble bien :)

          • [^] # Re: Performance

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

        • [^] # Re: Performance

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

          il est beaucoup plus simple d'écrire des tests, mais vraiment beaucoup. Le duck typing (ou le typage structurel) est un bonheur pour ça

          Il y a tout un tas de test que tu fais en python qui sont simplement inutiles en C++ du fait du typage statique de C++.

          il existe un outillage autour de python beaucoup plus riche que pour C++. Par exemple pour reprendre mon premier point, tu es beaucoup plus aidé pour passer de python2 à python3 que pour passer mettre à jour ta base de code C++ vers le nouveau standard.

          Il existe aussi des outils pour t'aider à améliorer ton code (il te propose même de patcher ton code directement).

          • [^] # Re: Performance

            Posté par  . Évalué à 5.

            Il y a tout un tas de test que tu fais en python qui sont simplement inutiles en C++ du fait du typage statique de C++.

            Le typage ? Tu n'écrit pas un test en python pour vérifier ton typage. Sinon c'est que tu n'utilise pas l'outil comme il faut. Le principe même du duck-typing fais que la notion de type n'a rien à voir et que tu ne fais pas les mêmes hypothèses sur ce qui t'es donné. La vérification du type n'est qu'un effet de bord de tes tests fonctionnels.

            Par contre on ne teste pas la cohérence de la mémoire en python. Donc pas besoin de valgrind et vu la complexité de mise en place de valgrind (il faut jouer des scénarios etc). Je pense que tu y gagne.

            Il existe aussi des outils pour t'aider à améliorer ton code (il te propose même de patcher ton code directement).

            Trop cool ! J'espérais voir apparaître un outil comme ça avec llvm l'ouverture de gcc, ils ont fini par le créer c'est super. Il est même capable de te pousser à faire du code moderne c'est parfait :) La dernière fois que j'avais cherché je n'avais rien trouvé.

            • [^] # Re: Performance

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

              Par contre on ne teste pas la cohérence de la mémoire en python. Donc pas besoin de valgrind et vu la complexité de mise en place de valgrind (il faut jouer des scénarios etc). Je pense que tu y gagne.

              Presque plus personne n'utilise valgrind de nos jours, sauf pour du debugging. ASAN et BSAN de g++ et clang++ font 95% pourcent du boulot de valgrind, sans les problèmes de performances, et sans la complexité de mise en oeuvre.

              • [^] # Re: Performance

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

                Tiens justement, aurais-tu une solution pour lancer Valgrind sur une app lié à libasan ? De souvenir c'était incompatible et l'app plantait tristement au lancement avec Valgrind.

              • [^] # Re: Performance

                Posté par  . Évalué à 1.

                ASAN et BSAN de g++ et clang++ font 95% pourcent du boulot de valgrind, sans les problèmes de performances, et sans la complexité de mise en oeuvre.

                Si je comprends bien ça reste runtime. Je présume que ce n'est pas utilisé pour du code de prod, il faut passer les tests avec l'instrumentation qui va bien. Même si c'est cool, ça reste une classe de bug que l'on trouve en C++ et qu'on ne trouve pas en python.

                • [^] # Re: Performance

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

                  Je présume que ce n'est pas utilisé pour du code de prod

                  Bah… Si tu es prêt à accepter la perte de vitesse et la consommation de RAM de l'équivalent en Python, j'imagine que tu es prêt à garder ASAN (perf divisée par 2, mémoire consommée multipliée par 4, "rien" par rapport à Python souvent :-D ) en prod.

                  Bref, comparer ce qui est comparable, quand on accepte des impacts de l'autre côté. Juste qu'en C++, la perte de perf est optionnelle ;-).

                  Même si c'est cool, ça reste une classe de bug que l'on trouve en C++ et qu'on ne trouve pas en python.

                  Ca a déjà été dit par ailleurs, mais cette bataille de "classe de bug" est toujours biaisée par la personne qui attaque, elle "oublie" comme par hasard les classes de bugs (ou la conso) dans son langage préféré qui ne se trouve pas dans le langage attaqué.

                  • [^] # Re: Performance

                    Posté par  . Évalué à 2.

                    Bref, comparer ce qui est comparable, quand on accepte des impacts de l'autre côté. Juste qu'en C++, la perte de perf est optionnelle ;-).

                    AMHA tu te trompe de comparaison. Sinon en comparant ce qui est comparable, tu peux implémenter le runtime python en C++ et là tu es comparable. Il me semble que la démarche que nous poursuivions avant que tu arrive consistait à comparer les pratiques dans divers langages. Dis autrement on tente de répondre à la question : « Comment est-ce que les développeurs python et C++ s'assurent de la qualité de logiciel ? » (ce qui est différent de la question « Comment on peut réimplémenter l'un dans l'autre »1). Je ne vois pas en quoi ça ne serait pas comparable.

                    Je doute que les développeurs C++ laissent l'instrumentation asan en prod. Ça pose tout de même un sacré paquet de problème. Et au contraire je ne vois pas en quoi une instrumentation qui va alerter et/ou crasher ton programme serait équivalent à un runtime qui gère la mémoire pour toi.


                    1. qui ne peut que mener à un « toute chose est égale par ailleurs » pas particulièrement intéressante. 

              • [^] # Re: Performance

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

                Presque plus personne n'utilise valgrind de nos jours

                Wat ? ça fait plusieurs fois que je lis ce genre de chose et y'a un truc qui m'echappe. Quel sanitizer tu utilises pour chopper les problemes de variable non initialisées ? Valgrind les choppe bien, mais ni asan ni ubsan ne signalent un probleme avec:

                int main(int argc, char **argv) {
                int i;
                std::cout << "i=" << i << "\n";
                return 0;
                }

                # g++-8 -fsanitize=address,undefined t.c && ./a.out
                i=0
                # g++-8 t.c && valgrind ./a.out
                Conditional jump or move depends on uninitialised value(s) (…)

                Accessoirement, le gain de temps d'execution pour moins il est perdu en temps de compilation et de link qui est au bas mot 2x plus long que sans sanitizers.

                • [^] # Re: Performance

                  Posté par  . Évalué à 2.

                  Quel sanitizer tu utilises pour chopper les problemes de variable non initialisées

                  L’option -Wuninitialized de GCC ou Clang :p

                  Mais ouais, pour les cas plus complexe Valgrind est bon, et les différents sanitizer ne supportent par encore tout ce que fait Valgrind.
                  Mais bon utiliser l’un n’empêche pas d'utiliser l’autre (par contre pas en même temps xD) : tu peux faire exécuter ta test suite sous Valgrind puis refaire une exécution compilé avec les sanitizer.

          • [^] # Re: Performance

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

            Il y a tout un tas de test que tu fais en python qui sont simplement inutiles en C++ du fait du typage statique de C++.

            Ca, c'est du troll pur non ?

            J'ai beau réfléchir, sur 15 ans de Python, les fois où j'ai du faire un test de typing pur en Python doivent se compter sur les doigts d'une main. Par contre, je profite régulièrement de la souplesse du typage de Python dans mes fonctions pour faire des trucs assez complexes qui, à faire en C++, demanderaient soit une classe dédiée, soit des template, soit d'être un expert C++18, soit les trois en même temps. Il y a beaucoup moins de boilerplate en Python.

            Et mes tests Python sont souvent bien plus poussés que ceux que j'écris en C++ pour des fonctionnalités équivalentes, et ce pour plusieurs raisons:

            • Python dispose d'un écosystème très étendu, permettant d'avoir pas mal de fonctionnalités déjà testées dans des lib externes, ce qui me permet de me concentrer sur des parties de mon code plus sensibles.
            • En jouant sur les Mock et les propriétés dynamiques de Python, il est plus facile d'aller tester du code en profondeur.
            • comme c'est plus rapide d'écrire du code en Python, l'écriture du code de test est aussi plus rapide, et à budget temps constant, je peux écrire plus de test, ou des tests qui vont plus en profondeur.

            Il existe aussi des outils pour t'aider à améliorer ton code (il te propose même de patcher ton code directement).

            Ca tombe bien, Python aussi. Ca va du simple Linter à MyPy ou PyCharm qui te permet de vérifier la cohérence des types utilisés dans ton projet (à peu près comme un compilo C++). D'ailleurs, il y a un français qui a fait une super conférence à ce sujet au PyData Paris 2018: https://www.youtube.com/watch?v=URP2e7hEUFw&list=PLzjFI0G5nSsry3cm_k1tPOi9SRaAXsZAt&index=6 (disclaimer: c'est moi qui présente).

            • [^] # Re: Performance

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

              En fait il y a typage et typage, et derrière ce mot il n'y a pas forcément les même notion.

              Le premier niveau, celui que tout le monde connaît, consiste à décrire la manière dont la donnée est représentée en mémoire. int, string, void etc. Sur ce sujet, je pense que tout le monde est d'accord on ne fait pas de test :)

              Le deuxième niveau, consiste à ajouter de l'information supplémentaire. Par exemple en C, int et unsigned int ont la même représentation mémoire, mais le fait d'avoir deux types différents permet (ou devrait permettre…) les erreurs bêtes. Il y a quelques années, un journal sur les types fantômes avait été posté, mais on peut imaginer des usages variés : par exemple une chaîne de texte (type string) ne donne pas d'information sur son contenu (encodage local, UTF-8 etc). En précisant cette information dans son type, on évite les erreurs bêtes d'encoder un texte qui l'est déjà. Et comme l'information est précisée au niveau du typage, cela est fait sans surcoût en mémoire, ni perte de performance à l'exécution, c'est le compilateur qui s'occupe de contrôler que les données sont adéquates.

              Je prend autre un exemple : dans un arbre rouge noir, il y a des propriétés à respecter pour garantir que l'arbre soit équilibré. Ces propriétés ne sont pas liées à la données contenue dans chaque nœud, et l'on pourrait penser que cela n'est pas lié à notre propos. Sauf qu'avec des notions de typage avancé, on peut laisser le compilateur garantir que le programme utilise notre arbre de façon appropriée. Cela veut dire que le programme ne compilera pas si un nœud rouge est inséré sous un autre nœud rouge. Le développeur n'a pas besoin de faire de test sur ces propriétés, elle sont garanties par le code.

              Cela ajoute de la complexité au code écrit, mais avec l'habitude, ça n'est pas un problème supplémentaire.

              • [^] # Re: Performance

                Posté par  . Évalué à 3.

                Tu utilise l'une des approche du typage celle du typage statique et oui on peut encoder potentiellement ce que l'on veut dans les types et le typage est prouvé par le compilateur.

                Là où une approche structurelle plutôt que par nom se démarque c'est que l'approche structurelle ne regarde pas la forme de la donnée en mémoire mais les propriétés qu'elle possède. Si je peux appeler les la méthode foo() sur ta variable on ne s'intéresse pas à qu'elle est la forme de cette donnée. C'est une souplesse qui est très structurante et elle évite d'avoir des arborescences de classes complexes et pas toujours pertinentes. On peut le vérifier dynamiquement comme en python ou statiquement comme en go.

                Avec le typage dynamique on a beaucoup plus d'informations de typage au runtime. C'est très utile quand tu fais des programmes configurés par les données par exemple.

                Après tu parle de cas général le typage du C++ est relativement pauvre, on peut faire des circonvolutions pour tenter d'encoder des choses en plus dans les types à coup de templating, mais plus aucun humain ne sera en mesure de reprendre le code en question.

                • [^] # Re: Performance

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

                  Pour être franc, j'avais plutôt en tête les langages fonctionnels (OCaml, Haskell), mais je répondais surtout à la question de savoir si le typage pouvait éviter de faire des tests ou non.

                  Je ne vois pas trop où tu veux en venir quand tu dis : avec le typage dynamique on a beaucoup plus d'informations de typage au runtime (ou alors j'ai peur de comprendre ce que tu proposes. Mon avis personnel est que le typage dynamique induit des risques et ne garantie pas que le programme soit sûr, mais c'est un autre débat dont il n'est pas l'objet ici).

                  Pour ton dernier point, je ne suis pas expert en C++ (et je ne souhaite pas l'être), mais quand je vois que certains prennent plaisir à écrire du brainfuck, je me dit que l'on peut tout à fait prendre plaisir à écrire ce genre de code via template (en tout cas certains le font en java) :)

                  • [^] # Re: Performance

                    Posté par  . Évalué à 2.

                    Pour être franc, j'avais plutôt en tête les langages fonctionnels (OCaml, Haskell), mais je répondais surtout à la question de savoir si le typage pouvait éviter de faire des tests ou non.

                    Oui mais tu réponds à une comparaison entre C++ et python. Donner un exemple pourquoi pas venir dire que le langage foobar lui il est mieux, c'est hors sujet.

                    Je ne vois pas trop où tu veux en venir quand tu dis : avec le typage dynamique on a beaucoup plus d'informations de typage au runtime (ou alors j'ai peur de comprendre ce que tu proposes. Mon avis personnel est que le typage dynamique induit des risques et ne garantie pas que le programme soit sûr, mais c'est un autre débat dont il n'est pas l'objet ici).

                    Le RTTI pour parler avec des termes plus précis. Le typage dynamique ne convient pas à toutes les situations et certaines approches statiques peuvent résoudre des problèmes auparavant traitées par le typage dynamique, mais il y a des fois où tu ne peux faire que peux d'hypothèses sur les données d'entrées par exemple, d'autres fois tu va vouloir cloner une structure sans pour autant la connaître initialement, tu as aussi des approches qui vont se rapprocher de l'AOP ou des proxy qui peuvent être infiniment plus simples,…

                    La question n'est pas de savoir si toi ou moi on aime ça (j'aime le turquoise, je présume que ça te fait une belle jambe), mais de savoir à quoi sert le typage dynamique et donc comment s'en servir et quand est-ce qu'il est pertinent. Le plus mauvais système de type, c'est celui qui est mal utilisé.

                    • [^] # Re: Performance

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

                      Je n'ai pas annoncé que tel langage était mieux qu'un autre, et je suis d'accord pour dire que la question n'est pas de savoir ce que l'on aime ou non (tu noteras que je disais déjà dans mon commentaire que ça n'était pas l'objet).

                      Ce que tu dis sur le RTTI est peut-être juste, mais je te trouve agressif dans ta réponse. Vu que c'est mon ressenti, et qu'il figure dans une discussion sur le typage, c'est peut-être également hors sujet ? (je t'avoue que j'ai hésité à répondre ne voulant pas ajouter du bruit dans cet échange qui prend d'un coup une tournure désagréable…)

                      • [^] # Re: Performance

                        Posté par  . Évalué à 2.

                        Ce que tu dis sur le RTTI est peut-être juste, mais je te trouve agressif dans ta réponse.

                        Tu m'en vois sincèrement désolé, ce n'était vraiment pas mon objectif. J'ai essayé d'apporter réellement quelque chose dans mes commentaires. Notamment on assez peu de gens qui explique à quoi sert un typage dynamique par ici, donc ça me paraissait intéressant. Si j'ai paru agressif ce n'était pas du tout mon intention.

                        • [^] # Re: Performance

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

                          Je n'ai pas bien vu ce qu'apporte le typage dynamique. Les avantages me semblent liés au typage structurel qui peut être vérifié statiquement comme en Ocaml.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 4. Dernière modification le 04 juin 2019 à 18:32.

                            Je pense que l'exemple le plus parlant sera le proxy.

                            Le proxy en POO c'est le fait de créer un objet qui s'utilise comme l'objet proxifié. On utilise le proxy sans savoir qu'il s'agit du proxy et pas de l'objet d'origine. Le proxy va pouvoir faire quelque chose avant, après et/ou à la place de l'objet qu'il proxyfie.

                            Il peut y avoir différents cas d'usage à ça : ajouter un cache à un objet, faire des vérifications de sécurité, mettre en place un circuit breaker, avoir du log, mettre en place un pattern stratégie,…

                            Pour faire ça en POO tu as besoin de faire de la délégation, mais j'ai pas vu beaucoup de langages courants qui permettent vraiment de faire de la délégation propre. Avec un langage dynamique, c'est assez simple à mettre en place.

                            Il existe d'autres façons de faire (java a une API de proxy par exemple), mais c'est un point qui est tout de même facilité par un typage dynamique.

                            • [^] # Re: Performance

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

                              Je pense que tu connais déjà, c'est moyen "propre" (je ne l'utilise pas des masse), il y a l'annotation Delegate directement en Groovy.

                              @TupleConstructor
                              class SelectOptionList {
                                  @Delegate
                                  List<SelectOption> selectOptions
                              // . . .
                              }

                              SelectOptionList s'utilise comme une liste.

                              • [^] # Re: Performance

                                Posté par  . Évalué à 2.

                                Qui est un langage dynamique :p

                                Mais je ne dis pas qu'il n'existe pas d'autres façon de faire. Par contre la solution que tu montre ne permet pas (il me semble) d'ajouter du code autour des appels délégués.

                                • [^] # Re: Performance

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

                                  Tu veux dire faire de l'AOP (version générale du Proxy)?

                                  ça se fait en Java, avec AspectJ par exemple. C'est vrai que ce n'est pas simple.

                                  • [^] # Re: Performance

                                    Posté par  . Évalué à 2.

                                    Les aspcts sont une façon d'implémenter des proxy, mais ce n'est ni la seule façon ni la façon la plus logique.

                                    En java standard tu as la classe Proxy par exemple (qui fait grand usage des RTTI). Spring implémente ces proxies soit via Proxy soit via de l'AOP (AOP par défaut depuis la version 5).

                                    Au dessus il est question de groovy, le metaobject protocol peut aussi servir à ça.

                            • [^] # Re: Performance

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

                              C'est en effet un exemple intéressant !

                              Si tu veux un proxy parfait qui prend n'importe quel objet et remplace toutes les méthodes par une méthode wrappée qui ajoute du comportement, en effet, tu feras cela très facilement en python, plus difficilement que dans d'autres langages moins dynamiques.

                              Si tu en veux faire un proxy de seulement une méthode / fonction. C'est assez simple (et tu peux le faire de façon assez générique) en C++ en créant un "functor" et en exploitant des templates variadics. Cependant le type de l'objet va changer (i.e. ce sera celui du Proxy) et donc il faudra que tes fonctions acceptants l'objet initial puisse accepter le nouveau. Si tes fonctions sont initialement "templatées", c'est faisable, sinon, c'est mort. Point de plus pour le langage dynamique.

                              Un point où un langage statique s'en sort très bien ce serait le cas du proxy d'une fonction. En prog fonctionelle, on a très souvent tendance à passer des fonctions en argument d'autres fonctions. Le type d'une fonction étant défini juste par ses arguments / valeur de retour, si ton proxy à la même interface, cela passera sans problème.

                              Par exemple, en Haskell, la fonction databaseQuery :: DbHandle -> Query -> IO DBResult qui prend une requete SQL et retourne un résultat, pourra être remplacée en ajoutant du log de la façon suivante:

                              log f arg = do
                                 putStrLn "Avant la fonction"
                                 res <- f arg
                                 putStrLn "Après la fonction"
                                 pure res

                              Ainsi, que tu passes dataBaseQuery handle ou log (dataBaseQuery handle) (i.e. ton proxy) en argument d'une autre fonction, le système de type sera satisfait.

                              Cependant cela demande de penser son interface en avance et c'est donc moins souple. De mon expérience, je suis rarement limité par ce point, mais j'admet cette limitation.

                              Merci de m'avoir fourni un exemple valide de l’intérêt d'un typage dynamique.

                              • [^] # Re: Performance

                                Posté par  . Évalué à 2.

                                Cependant le type de l'objet va changer (i.e. ce sera celui du Proxy) et donc il faudra que tes fonctions acceptants l'objet initial puisse accepter le nouveau. Si tes fonctions sont initialement "templatées", c'est faisable, sinon, c'est mort. Point de plus pour le langage dynamique.

                                C'est pas le dynamisme qui joue là, mais le stypage structurel/duck typing.

                                Le type d'une fonction étant défini juste par ses arguments / valeur de retour, si ton proxy à la même interface, cela passera sans problème.

                                Elles bénéficient d'un typage structurel. C'est la forme de la fonction qui donne son type et pas son nom. On peut imaginer des langages où tu peut définir le type injectionInt qui est un type de fonction qui pour tout entier te renvoie un entier et qui t'obligerais à déclarer des fonctions add, mult,… comme étant du type injectionInt. Tu n'aurais plus de typage structurel et les même problèmes qu'avec les objets.

                                Cependant cela demande de penser son interface en avance et c'est donc moins souple. De mon expérience, je suis rarement limité par ce point, mais j'admet cette limitation.

                                C'est un usage qui arrive pour ceux qui font de grosses bibliothèques (injection de dépendance par exemple).

                                Merci de m'avoir fourni un exemple valide de l’intérêt d'un typage dynamique.

                                De rien :)

                            • [^] # Re: Performance

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

                              Vu la définition et les cas d'usage que tu cites, un proxy ne serait-il pas implémentable avec une classe abstraite en C++ ?
                              Je pose cette question pas tant pour faire avancer le débat que pour voir s'il n'y a pas quelque chose qui m'échappe…

                              Cyberdépendance, cyberharcèlement, pédocriminalité… : Zelbinium, pour que les smartphones soient la solution, pas le problème !

                              • [^] # Re: Performance

                                Posté par  . Évalué à 2.

                                Je pose cette question pas tant pour faire avancer le débat que pour voir s'il n'y a pas quelque chose qui m'échappe…

                                Le découplage entre le proxy et l'objet proxifié. Tu peux vouloir proxifier des objets d'une bibliothèque dont tu n'a pas la charge du code source et tu voudrais alors que l'évolution de cette bibliothèque ne te coûte le moins possible (ajout, suppression, changement des méthodes de cet objet).

                                De l'autre coté d'un point de vu utilisateur le fait que l'objet soit proxifié devrait être transparent (par définition un proxy doit avoir un contrat équivalent, sinon c'est un adapteur). Donc tu ne devrais pas toucher au typage pour ça.

                                Ce sont 2 grosses contraintes mais elles donnent une grande flexibilité et ce n'est pas des cas théoriques. Spring est très largement basé sur des proxies par exemple (il ne le fait pas comme ça, mais s'ils pouvaient ils le ferraient).

                                Dans les autres façons de faire que je vois il y a :

                                • utiliser de l'AOP, tu patch le code ou le code généré
                                • utiliser MOP de groovy (mais le __call() de php peut faire la même chose) intercepter les appels vers ton objet
                                • java possède une API spécifique aux proxy
                                • [^] # Re: Performance

                                  Posté par  (site web personnel) . Évalué à 3. Dernière modification le 09 juin 2019 à 13:18.

                                  Corrige moi si je me plante quelque part :

                                  template<typename Proxified> class proxy : public Proxified {
                                  public:
                                       explicit proxy(Proxyfied && origin) : Proxified(std::move(origin) {}
                                  
                                       // define here all my method orverride for my proxy
                                       virtual int my_proxy_method() override{};
                                  };
                                  
                                  

                                  Est-ce que ce snippet ne ferait pas le boulot pour une re-definition statique ET proxyfié que tu recherches en C++ ?

                                  • L'intégralité des methodes et propriétés de "Proxified" sont disponible dans l'interface de ton objet proxy.

                                  • Tu peux override à souhait toute methode de "Proxyfied".

                                  • Le tout a un impact en terme de performance null si ta classe supporte correctement le move-semantic.

                                  • [^] # Re: Performance

                                    Posté par  . Évalué à 2.

                                    Ça peut faire l'affaire :)

                                    Les défauts que je vois :

                                    • c'est beaucoup moins agréable pour faire des proxies génériques. Par exemple le cas d'un circuit breaker. L'algo autour de ton appel est le même pour tout tes appels. Dans ton cas si tu peut factoriser cet algo tu va tout de même avoir un boiler plate pour chaque méthode proxifiée
                                    • encore avec mon exemple du circuit breaker : tu as un couplage dans un sens, ce qui empêche d'avoir le proxy dans une bibliothèque. C'est un aspect très contraignant dans les langages statiques, mais c'est très agréable à l'usage de ne pas avoir ce couplage (oui ça a un coût non négligeable)
                                    • évidement ça ne marche que pour les méthodes virtuelles des classes non final

                                    Je pense sincèrement que c'est l'un des cas où l'AOP a du sens (je suis contant d'avoir trouvé un cas d'usage amha pertinent à l'AOP :) ). Ça permet de remplir tous les critères : souplesse d'un langage dynamique sans aucun coût à l'exécution.

                                    Merci sincèrement pour l'exemple qui peut être pertinent dans beaucoup de cas.

                        • [^] # Re: Performance

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

                          Pas de soucis, c'est le lot des échanges sur le net, ça n'est jamais simple… et pourtant ça marche !

                          :)

                    • [^] # Re: Performance

                      Posté par  . Évalué à 3.

                      Oui mais tu réponds à une comparaison entre C++ et python. Donner un exemple pourquoi pas venir dire que le langage foobar lui il est mieux, c'est hors sujet.

                      Ce n'est pas vraiment hors-sujet à mon avis. Philippe Fremy répond à rewind en postant une vidéo d'une de ses conférences sur le typage statique en python. Le slide de conclusion est :

                      Conclusion :

                      • Type annotation is powerful to bug finder. Use it !
                      • Type annotation is also good way to document your code.
                      • Feedback from developpers using type annoation: "It rocks !"
                      • Some python dynamic constructs are difficult to verify statically

                      Là où c'est déjà étrange, c'est que dans sa réponse il laisse entendre que rewind cherche à troller, alors que c'est justement ces avantages du typage statique que rewind et chimrod ont cherchait à mettre en avant.

                      Ensuite, oui cela relève d'une plus grande sûreté que le recours aux tests unitaires. Quand on pousse jusqu'aux systèmes à types dépéndants, non seulement on ne fait plus de tests unitaires mais en plus on obtient une sûreté que ne pourront jamais atteindre ces derniers : un test peut montrer l'existence d'un bug (dans le respect à la spécification) mais jamais son absence.

                      Typer son code permet effectivement de le documenter (point 2 du slide de conclusion) car le langage de types est un langage formel d'écriture de spécification du code, et permet donc d'exprimer en partie ce que doit faire la fonction. D'où mon point précédent, avec des types dépendants on peut totalement spécifier formellement le code et donc vérifier qu'il est conforme à sa spécification.

                      Pour le typage structurel, on peut tout à fait faire cela statiquement et sans écrire d'annotation. Quelques exemples issues de la conférence de Philippe Fremy :

                      (* voir à la 20ème minute *)
                      
                      (* cas d'un bug détecter statiquement *)
                      class a ?step_init = object
                        val step = step_init
                        method get_step = step_init + 1
                      end;;
                      Error: This expression has type 'a option
                             but an expression was expected of type int
                      
                      (* première solution on teste la valeur de l'attribut [step] *)
                      class a ?step_init () = object
                        val step = step_init
                        method get_step = match step with None -> 0 | Some step-> step + 1
                      end;;
                      class a :
                        ?step_init:int ->
                        unit -> object val step : int option method get_step : int end
                      
                      (* deuxième solution, on initialise avec une valeur par défaut *)
                      class a ?(step_init = 0) () = object
                        val step = step_init
                        method get_step = step + 1 end;;
                      class a :
                        ?step_init:int -> unit -> object val step : int method get_step : int end
                      
                      
                      (* pour le typage structurel, voire autour de la 30ème minute *)
                      let validate form data = form#validate data;;
                      val validate : < validate : 'a -> 'b; .. > -> 'a -> 'b = <fun>

                      Enfin, pour ce qui est des objets et du typage structurel, la façon dont ils sont globalement utilisés en pratique cela en fait surtout des modules du pauvre. En OCaml on utilisera plutôt des modules, en Haskell des type classes, en Rust des traits et en C++ des template.

                      Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                      • [^] # Re: Performance

                        Posté par  . Évalué à 3.

                        Pour le typage structurel, on peut tout à fait faire cela statiquement et sans écrire d'annotation.

                        C'est ce que fait go. Typescript a un typage structurel vérifié à la compilation, mais il est optionnel.

                        Enfin, pour ce qui est des objets et du typage structurel, la façon dont ils sont globalement utilisés en pratique cela en fait surtout des modules du pauvre. En OCaml on utilisera plutôt des modules, en Haskell des type classes, en Rust des traits et en C++ des template.

                        L'intérêt c'est de pouvoir avoir un polymorphisme qui ne soit pas nommé. Quand on veut créer une méthode qui va manipuler des données qui ont un id qui est un UUID par exemple. Le typage structurel peut permettre d'avoir des données qui ne sont pas liées entre elles, mais qui possèdent toutes un id de la bonne forme.

                        Je ne connais pas les autres, mais je ne suis pas certains que C++ permettent d'être aussi souple que go. En go (et c'est pour moi le gros intérêt), ta structure n'a pas a connaître la structure nécessaire à ta méthode pour être utilisable.

                        package main
                        
                        import "fmt"
                        
                        type User interface {
                            Greeting() string
                        }
                        
                        type Plouf struct {
                            FirstName, LastName, Addr string
                        }
                        
                        func (p Plouf) Greeting() string {
                            return fmt.Sprintf("Dear %s %s", p.FirstName, p.LastName)
                        }
                        
                        func Foo(u User) {
                            fmt.Println(u.Greeting())
                        }
                        
                        func main() {
                            u := Plouf{"Matt", "Aimonetti", "chez moi"}
                            Foo(u)
                        }

                        Le type Plouf n'a aucun rapport avec l'interface User. Ça permet d'écrire après coup des fonctions qui définissent des interfaces décrivant le contrat que doivent remplir leur arguments sans impact sur les types créé ailleurs. Dans l'usage on peut généraliser une fonction à un ensemble de type qui sont dans différentes bibliothèques. Je sais pas si c'est très clair…

                        En java je fais un hack a coup de lambda pour ça.

                        • [^] # Re: Performance

                          Posté par  . Évalué à 4. Dernière modification le 05 juin 2019 à 17:59.

                          Je sais pas si c'est très clair…

                          Ça l'est : tu veux faire du polymorphisme ad-hoc; mais je ne vois pas où on a besoin de typage dynamique pour cela.

                          L'idée du polymorphisme ad-hoc est d'avoir des fonctions qui ont le même nom (ici Greeting) mais qui opère sur différents types et selon des logiques différentes (à la différence du polymorphisme paramétrique). Ensuite à l'usage (comme dans ta fonction foo) la fonction effectivement utilisée est choisie en fonction du type du paramètre (type base dispatch). C'est exactement ce que font les type classes de Haskell et les traits du Rust. Cette manière de faire est bien plus intelligente (j'ai envie de dire moins inepte) que l'approche de l'orienté objet. En OCaml on passe par des modules et foncteurs pour faire cela (avec une perte de l'implicite) et il me semble (mais là je suis moins sûr) que les template du C++ peuvent servir à cela.

                          Pour présenter grossièrement l'idée, il s'agit d'associer à un type un dictionnaire de fonctions pour opérer dessus, c'est l'interface contre laquelle on veut programmer de manière générique. En fonction du type du paramètre, le compilateur choisira le dictionnaire qui lui a été associé. Néanmoins, le système des interfaces du Go reste trop limité à mon goût : j'en ai déjà parlé sur un ancien journal de gasche.

                          Prenons l'exemple de la structure d'anneaux en mathématiques : un anneau c'est un type de données que l'on peut ajouter, soustraire et multiplier avec deux éléments neutres pour l'addition et la multiplication. Autrement dit, c'est cette interface de module :

                          module type Anneau = sig
                            (* le type des éléments de l'anneau *)
                            type t
                          
                            (* les éléments neutres *)
                            val zero : t
                            val one : t
                          
                            (* les opérations *)
                            val add : t -> t -> t
                            val neg : t -> t
                            val mul : t -> t -> t
                          end

                          Plutôt que de dire que l'on peut les soustraire, je préfère exprimer l'axiomatique en disant que l'addition est une opération inversible d'où la fonction neg. À partir de là, dès que l'on a une telle structure, on peut définir dessus le polynôme X^{2} + X + 1 :

                          let f (type a) (module A : Anneau with type t = a) x =
                            let (+), ( * ) = A.add, A.mul in
                            x * x + x + A.one

                          Le principe derrière les type classes de Haskell ou les traits de Rust est de dire que pour un type donnée on ne peut définir qu'une interface Anneau sur ce type. Autrement dit, ils considèrent que le type Anneau with type type t = a est un singleton pour tout type a (où plutôt le compilateur garantie que l'on ne définit pas deux valeurs distinctes de ce type), ce qui est trivialement faux mais en pratique largement suffisant. Les interfaces de Go, c'est un peu la même idée mais en beaucoup moins bien : tu ne peux pas définir l'interface Anneau par exemple, il n'est pas possible de définir des opérateurs binaires sur le type t dans les interfaces de Go.

                          En OCaml, comme le type en question est rarement un singleton, il faut explicitement passer le dictionnaire en argument à la fonction f, même s'il y a déjà eu des propositions pour le rendre implicites dans certaines situations.

                          Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 2. Dernière modification le 05 juin 2019 à 18:03.

                            Ça l'est : tu veux faire du polymorphisme ad-hoc; mais je ne vois pas où on a besoin de typage dynamique pour cela.

                            Mon exemple utilise un langage avec un typage statique ;)

                            • [^] # Re: Performance

                              Posté par  . Évalué à 4. Dernière modification le 10 juin 2019 à 13:14.

                              Je sais bien que Go fait du typage statique (même s'il fait fait du typage dynamique pour la généricité avec l'interface {}). Ce que je voulais dire c'est que le problème que tu cherchais à illustrer ne relève pas de la distinction typage dynamique vs. typage statique, mais d'une limitation du paradigme objet et de la façon dont il gère le polymorphisme ad-hoc. Go n'est pas orienté objet, tout comme Haskell ou Rust ne le sont pas. En Haskell ton code passera par des type classes :

                              class User a where
                                 greetings :: a -> String
                              
                              data Plouf = Plouf { FirstName :: String, LastName :: String, Addr :: String }
                              
                              instance User Plouf where
                                grettings user = ...

                              En Rust, ce sera par des traits, ce qui n'est pas de l'orienté objet.

                              Pour illustrer la distinction entre l'approche objet et celle de Go, Haskell et Rust, faisons cela en OCaml.

                              Selon le paradigme objet, on aurait une méthode greetings sur notre objet

                              class fst_name last_name addr = object
                                val fst_name = fst_name
                                val last_name = last_name
                                val addr = addr
                                method greetings () = Printf.sprintf "Dear %s %s" fst_name last_name
                              end

                              et la fonction foo appellerait cette méthode sur notre objet

                              let foo o = print_endline (o#greetings ())
                              
                              let u = new plouf "Matt" "Aimonetti" "chez moi" in foo u;;
                              (* le retour *)
                              Dear Matt Aimonetti

                              Dans l'approche objet, les opérations sur le triplet de string ne sont pas dissociables du types : c'est un tout. Ce que tu exprimais dans ton commentaire ainsi :

                              Le type Plouf n'a aucun rapport avec l'interface User. Ça permet d'écrire après coup des fonctions qui définissent des interfaces décrivant le contrat que doivent remplir leur arguments sans impact sur les types créé ailleurs.

                              Dans l'approche objet, le dictionnaire de méthodes (ici User) et le type sur lequel elles opèrent (ici Plouf) sont indissociables. Dans l'approche de Go, Haskell ou Rust le dictionnaire de méthode et le type sont dissociés. C'est ce que j'ai cherché à expliquer dans ma réponse précédente, et c'est aussi la raison pour laquelle en OCaml on passera par des modules et non des objets pour modéliser une telle problématique.

                              (* la version OCaml de la type classe Haskell *)
                              module type User = sig
                                type t
                                val greetings : t -> string
                              end
                              
                              module Plouf = struct
                                type t = {
                                  first_name : string;
                                  last_name : string;
                                  addr : string
                                }
                              
                                let greetings {first_name; last_name; _} =
                                  Printf.sprintf "Dear %s %s" first_name last_name
                              end
                              
                              let foo (type a) (module M : User with type t = a) x = M.greetings x

                              La différence ici, avec les trois autres langages, est que l'on peut définir plus d'un dictionnaire pour un même type : il doit donc être passer explicitement à la fonction foo. Là où, dans les autres langages, le dictionnaire étant unique pour un type donné, il est déterminé univoquement à partir du type de la variable x.

                              Pour bien illustrer la différence avec le paradigme objet, c'est cela le type d'un objet :

                              type 'a user_object = 'a * (module Meth : User with type t = 'a)

                              c'est la donnée conjointe d'une valeur de type 'a (les attributs de l'instance) et des méthodes sur ces attributs, conjonction que l'on ne peut séparer en ses composantes au niveau du système de type.

                              Ceci étant, bien que je trouve ce paradigme plus intelligent que celui du paradigme objet, la façon dont il existe en Go reste très limitée : tu ne peux pas surcharger des opérateurs binaires avec (addition, comparaison, test d'égalité…).

                              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                      • [^] # Re: Performance

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

                        J'ai beaucoup de mal à croire qu'il suffise de bien typer pour supprimer tous les bugs… Un peu comme si en physique, toute formule homogène était juste.

                        • [^] # Re: Performance

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

                          J'ai beaucoup de mal à croire qu'il suffise de bien typer pour supprimer tous les bugs…

                          Ça tombe bien, personne n'a dit ça, et c'est une bêtise. Ce que beaucoup disent (dont moi), c'est qu'un typage explicite permet d'éviter des bugs à la compilation parce qu'il y a une vérification du typage correct. Donc pas tous mais certains.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 3.

                            Ça tombe bien, personne n'a dit ça, et c'est une bêtise.

                            Je crois que c'est moi qui l'est dit, et ce n'est pas une bêtise : c'est ce qu'offre les langages avec types dépendants. Du moins il dispense de tests unitaires, sauf pour ce qui est des erreurs dans la formalisation des spécifications du code.

                            L'exemple le plus parlant est celui-ci :

                            Theorem transform_c_programm_preservation :
                              forall p tp beh
                              transf_c_program p = Ok tp ->
                              program_behaves (Asm.semantics tp) beh ->
                              exists beh', programm_behaves (C.semantics p) beh'
                                        /\ behavior_improves beh' beh

                            Laissant de côté le mot clef Theorem, le terme transform_c_programm_preservation est un terme du langage dont le type est l'énoncé exprimant que CompCert C est bien un compilateur C optimisant qui préserve la sémantique. Le terme, ou programme, est construit grâce à l'assistant de preuve Coq et il y a bien vérification statique qu'il a le bon type. Comme son type quantifie sur la totalité des programmes C (la varibale p du forall), qui est potentiellement infinie, il garantie des choses inaccessibles aux tests unitaires.

                            Par contre, il reste la question : la formalisation de la sémantique de l'Asm (utilisée dans le terme Asm.semantics tp) est-elle conforme à la réalité ? Question dont la réponse est inaccessible aux méthodes formelles. De même pour ce qui est de la question sur la correction de la formalisation du C.

                            Au niveau de la traduction en français, le type s'exprime ainsi : pour tout programme C p, tout programme assembleur tp et tout comportement observable beh, si la fonction transf_c_prgram appliquée à p renvoie le programme tp et que beh est un comportement observable de tp en accord avec la sémantique ASM, alors il existe un comportement observable beh' de p conforme à la sémantique du C et tel que beh améliore beh'.

                            Autrement dit le type affirme que transf_c_program est un compilateur optimisant du C vers l'ASM.

                            Ce cas extrême n'était pas pour inciter à l'usage des types dépendants, mais pour montrer que plus on introduit de typage statique et d'expressivité dans le système de types, moins on a besoin de tests unitaires (au point de ne plus en avoir besoin) : ce qui était bien ton propos initial. ;-)

                            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                            • [^] # Re: Performance

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

                              Mais en pratique, c'est rare (ou plutôt rarissime) d'avoir des spécifications formalisées au point de pouvoir prouver quoique ce soit (déjà qu'avoir des spécs n'est pas donné à tout le monde)…

                              • [^] # Re: Performance

                                Posté par  . Évalué à 4. Dernière modification le 06 juin 2019 à 01:04.

                                C'est certain, mais dans certaines fonctions de bibliothèques les spécifications sont bien connues et c'est ce que l'on teste avec les tests unitaires. Si je reprend, par exemple, mon interface Anneau d'un commentaire précédent, on doit avoir comme propriété que add x (neg x) = zero pour tout valeur de x. Ça s'exprime et se prouve en Coq, ce qui est hors de portée des tests unitaires.

                                Ceci étant, la référence aux systèmes avec typage dépendant avait pour seul but de justifier la proposition : plus on enrichit le système de types, moins on a besoin de tests unitaires. Proposition implicitement soutenue par rewind qui est à l'origine de cette sous discussion dans les commentaires.

                                Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                  • [^] # Re: Performance

                    Posté par  . Évalué à 2.

                    J'aurais plutôt pensé à de la programmation pas contrat comme le proposait Eiffel pour ma part:
                    https://www.eiffel.com/values/design-by-contract/introduction/

                    Ou alors je n'ai pas bien compris.

                • [^] # Re: Performance

                  Posté par  (site web personnel) . Évalué à 3. Dernière modification le 05 juin 2019 à 10:25.

                  Après tu parle de cas général le typage du C++ est relativement pauvre, on peut faire des circonvolutions pour tenter d'encoder des choses en plus dans les types à coup de templating, mais plus aucun humain ne sera en mesure de reprendre le code en question.

                  Le typage en C++ est tout sauf pauvre, le typage du C est pauvre.

                  Il s'approche au fil des standard de ce que tu peux avoir en Haskell et OCaml, qui sont des références dans le domaine.

                  std::variant autorise même maintenant à avoir une forme de pattern matching.

                  std::optional apporte lui aussi son lot d'avantages.

                  • [^] # Re: Performance

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

                    Dans ma vie de développeur C et C++, je suis régulièrement confronté au fait que les entiers soient un type "faible", c'est à dire sans limite précise.

                    Typiquement, j'ai un offset dans un tableau de taille fixe, mais il est représenté par un unsigned int (et encore, c'est quand je fais propre, le reste du temps, c'est un signed int). Et il peut circuler d'une fonction à une autre sous forme d'entier non signé, perdant complètement la notion de limite intrinsèque pour laquelle il a été défini. Le buffer overflow nous tend les bras et le compilateur ne peut rien faire pour le prévenir, c'est dans la définition du langage.

                    Beaucoup de bugs découlent de cette absence de typage, et les langages C/C++/Java ne font rien pour y remédier. Elle se retrouve sous plein de variantes : les Enum qui sont gérés comme des int par le compilateur, une structure définie avec des types ouverts (int, float, std::string), alors qu'en fait, seul un petit nombre de valeur sont autorisés pour ces champs, etc etc.

                    J'ai entendu dire que le bon langage pour tenir compte de ce genre de contrainte s'appelle Ada. J'ai encore jamais pris le temps ni l'énergie de m'y mettre, mais je suis persuadé que si je dois écrire un programme "sur", c'est vers lui que le me tournerai.

                    Quand on me dit que le C++ est typé, c'est vrai mais je me sens toujours pas en sécurité quand je l'utilise. Les buffers overflow et les déréferencements de pointeurs ont encore une longue vie devant eux.

                    Jusqu'à récemment, j'avais aussi la sensation de prendre des risques à coder un gros projet en Python. Depuis l'arrivée de Mypy et du typage dynamique, je suis plus tranquille. Je n'ai pas encore la sureté d'un langage compilé mais je trouve que le compromis "sureté / rapidité de développement / facilité de test" est très correct.

                    Quand je retourne au C et C++, je perds beaucoup sur les deux derniers points, et de mon point de vue, je ne gagne pas assez en sureté.

                    • [^] # Re: Performance

                      Posté par  . Évalué à 4.

                      J'ai entendu dire que le bon langage pour tenir compte de ce genre de contrainte s'appelle Ada.

                      Oui.

                      J'ai encore jamais pris le temps ni l'énergie de m'y mettre, mais je suis persuadé que si je dois écrire un programme "sur", c'est vers lui que le me tournerai.

                      C'est clair. Pour ma part je m'y suis intéressé. C'est un langage assez verbeux et l'appretissage est difficile. Il faut être précis sur tout, et ce langage confirme une généralité : faire les choses très bien et de façon sure, ça coûte. Et je suis certain qu'écrire un programme en ADA, même pour un expert du langage, ça coûte plus cher que d'écrire le même langage en Java (pour le c++ je sais pas : je serais d'avis, mais je peux me tromper, qu'écrire un soft en C++ prend autant de temps et d'énergie que de l'écrire en ADA, avec plus de risque de retrouver des bugs à la fin du développement parce que le langage n'est pas aussi "strict" qu'Ada). Par contre on est sur de ne pas rencontrer tout un tas de bugs qu'on pourrait rencontrer dans d'autres langages, et la maintenance est facilitée.

                      Pour ce que j'en ai vu, Rust me parait un bon compromis pour écrire des programmes plus sûrs qu'en C ou en C++, sans tomber dans le côté extrême d'Ada. Mais comme je ne suis pas expert dans le domaine, je peux me tromper (et je suis preneur de tout avis qui m'expliquerait en quoi je me trompe).

                      • [^] # Re: Performance

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

                        Sommaire

                        Étant développeur Ada depuis plus de 10 ans, je ne trouve pas qu'Ada soit si « extrême » que ça, ni difficile, mais c'est peut-être une déformation professionnelle de ma part… Je ne me considère pas guru en Ada.

                        Il y a le côté fortement typé du langage : au début, quand on vient du C/C++ ou Java, c'est nouveau et ça peut paraître plus difficile, mais rapidement on s'aperçoit que ça fait gagner du temps, car on peut borner beaucoup plus facilement le code à des plages de valeurs restreintes à son besoin, et empêcher de manipuler les variables n'importe comment. En C/C++ ou Java, t'es obligé de tester que ton argument d'entrée "int", "float" ou autre primitive, est correctement borné par rapport à ton attente. Parfois tu ne le fais pas, en te disant que ça a déjà été vérifié plus en amont dans le code, mais parfois tu te loupes (ou parce que soudain ta fonction est appelée d'ailleurs, sans vérification). En Ada, pas de soucis à se faire là-dessus. En fait, le code critique sera celui de la conversion de ta donnée d'entrée en donnée typée (c'est là que tu dois gérer les cas d'erreur possibles), mais il sera alors bien localisé, là où dans d'autres langages ça peut être plus flou (ou plus expéditif… avec son lot de bugs). Aujourd'hui, quand je manipule des variables de type primitives en C/C++/Java, j'ai vraiment l'impression de travailler sans filet de sécurité.

                        Mon point de vue maintenant sur les temps de développement, à partir de mon expérience perso. Je dirais que chaque langage a ses points forts (où l'on gagne du temps) et ses points faibles (où l'on perd du temps) et j'aurais bien du mal à les classer par ordre d'une manière générale.

                        Java

                        • Le côté dynamique de Java permet de démarrer le codage très rapidement. Écrire et exécuter un test unitaire dans Eclipse est extrêmement facile et rapide, et c'est très agréable. Tester la couverture de code sans son IDE également. La compilation est également rapide, les messages d'erreur suffisamment clairs pour comprendre ce qui ne va pas. Les conventions de nommage (voire de codage) fortement imposées permettent d'écarter les questions de base philosophiques qui font perdre du temps pour rien. Bref tu lance ton IDE, Nouveau Projet, et c'est parti !

                        • Le runtime Java est plutôt bien fourni, ça aide à coder rapidement également.

                        • Beaucoup de bibliothèques existantes, mais parfois en terme de dépendances, on a l'impression de tirer la mer et les poissons. Quand on travail sur des systèmes critiques où il faut maîtriser toutes les dépendances, il faut parfois apprendre à s'en passer (pareil pour les potentielles galères de licences).

                        • Là où ça se gâte à mon sens, c'est sur la partie packaging/déploiement, qui quand elle tourne mal, peut faire perdre pas mal de temps qu'on avait gagné en codage (et en général c'est pour des conneries). Certains outils sont censés simplifier ça en imposant une certaine structure (genre maven), mais d'une part je ne trouve pas la syntaxe de ces outils très fluide à manipuler, d'autre part, je suis souvent bloqué par un firewall très filtrant et je dois donc m'organiser comme si j'étais offline 100% du temps. Et là, ça coûte en temps pour la mise en place d'un environnement maven/nexus, l'import des dépendances (qui est devenu galère dans nexus 3), etc. Sur un gros projet, ces coûts pourront s'absorber, mais sur des petits programmes, ça peut parfois coûter plus que le temps de codage.

                        • Autre point ennuyant, c'est pour faire un simple programme, là où en C, C++ ou Ada tu obtiens un binaire prêt à l'emploi, avec Java t'as un ou plusieurs jar, qu'il faut lier en général avec un script de lancement, tout en s'assurant d'avoir le bon JRE, le bon environnement, etc., bref un peu pénible à gérer.

                        Ada

                        • En Ada, le côté verbeux rend forcément l'écriture de code plus lente (c'est tout de même atténué grâce à la complétion auto de l'IDE). Mais en même temps, c'est bien rare que j'arrive, dans n'importe quel langage, à écrire une fonction d'une traite de bout en bout sans me poser et réfléchir entre deux lignes.

                        • La séparation entre spec (header) et body (source) prends également du temps. Elle permet toutefois de bien séparer le contrat de l'implémentation (pratique pour faire du logiciel propriétaire ;-)). En Java, il n'y a que le code, et le côté dynamique du langage permet d'en extraire les signatures de classes facilement, reste la javadoc, qu'il faut fournir « à côté », là où en Ada on peut se contenter de lire les commentaires présents dans le fichier spec. En C++, c'est la fête du slip.

                        • La structure d'un programme Ada, en packages, présente les mêmes avantages que Java en terme d'organisation de code, et les packages s'importent simplement comme en Java, dans l'ordre qu'on veut. Le temps de compilation est généralement assez rapide (sauf cas particuliers), un peu comme en C je dirais, mais plus lent que Java.

                        • Le runtime Ada s'est pas mal étoffé ces dernières années, et propose pas mal de choses.

                        • Il n'existe pas beaucoup de bibliothèques en Ada, mais on peu faire des bindings avec les bibliothèques C assez efficacement (ça prend un peu de temps de développement).

                        • Côté outils, Ada étant un langage de niche, il n'y en a pas 36, du coup on perds pas beaucoup de temps à choisir ;), mais on trouve généralement ce qu'il faut.
                          L'IDE, GNAT Programming Studio (GPS), commence à être vraiment pas mal.

                        • Enfin, concernant la fabrication, là c'est c'est vraiment excellent. La description des projets dans des fichiers « .gpr » surpasse de loin tout ce que j'ai vu (Makefile, CMake & co) en terme de clarté, simplicité, rapidité à écrire et maintenir, réutilisation par divers outils (compilateur, IDE, analyseurs, …). En plus, ça marche aussi pour d'autres langages comme C et C++ (ou pour mixer plusieurs langages).

                        C++

                        Bon là je vais être méchant, et ça me rend bien triste. J'ai commencé la programmation avec C++, et j'étais fan de ce langage, mais je n'en ai pas fait beaucoup durant cette décennie. De temps en temps, j'essaie d'en refaire un peu histoire de pas trop perdre la main.

                        Quand aujourd'hui je compare le C++ à Java ou Ada, je trouve que :

                        • C'est un langage syntaxiquement compliqué. La STL me paraît également compliquée, et limitée. Il y a certaines fonctionnalités que je ne trouve pas alors que je les aurait facilement trouvées en Java ou Ada, ou alors elles existent mais sous une autre forme, propre au C++, mais donc je perds du temps à essayer de les trouver (je suis peut-être trop formaté Ada/Java). Aussi, peut-être je n'utilise pas les bons outils, mais voici un exemple de ce que me propose Eclipse lorsque je place le curseur sur ma variable de style vector:

                        Ça m'est totalement obscur. Voir ça en 2019 m'a fortement déçu sur l'évolution de C++ et de son écosystème. Et le bout de code en exemple, je l'ai trouvé sur le net. Tout seul je n'aurais pas su l'écrire, et d'ailleurs j'ai encore du mal comprendre comment il fonctionne (!), ce qui m'inquiète beaucoup.

                        Aussi je perds pas mal de temps à comprendre certains messages d'erreur de gcc (quand c'est pas de la bouillie templatique).

                        • D'un point de vue organisation du code, à cause du mécanisme archaïque des includes, c'est bordélique. Il faut les mettre dans le bon ordre sinon ça pète. Un truc comme ça en 2019 c'est vraiment difficile à supporter.
                          La séparation déclaration/implémentation entre header et source n'est jamais claire, puisqu'on trouve du code dans les headers, partiellement ou complètement. Et honnêtement, je passe (perds) souvent du temps à me demander comment je vais organiser mon code, est-ce que telle fonction je la définis dans le header ou pas, etc.
                          D'autre part, je me retrouve à inclure des headers de plusieurs dizaines de milliers de ligne de code (genre vulkan.hpp) dans mes fichiers sources, et je le sens bien en temps de compilation, on se retrouve alors bien plus lent que Ada ou Java.

                        • Concernant la fabrication, c'est pas encore la panacée à ce que je vois (Make, CMake, etc., communauté encore très fragmentée sur cette question), là où en Ada c'est très clair et simple, pourtant ce sont deux langages proches en terme de fabrication. Donc un peu de perte de temps à ce niveau. Point « positif » : à la fin, on a un binaire comme en Ada, donc de ce point de vue c'est plus simple à lancer hors d'un IDE qu'un programme Java.

                        Conclusion

                        Java: Hors écriture de code, Java dans l'IDE, c'est rapide, mais en dehors de l'IDE, c'est plus long.

                        Ada: Un peu plus long à écrire pour la verbosité, mais temps récupéré sur la qualité du code et des outils de développement. Développer en Ada ne coûte globalement pas plus cher qu'en C, C++ ni même Java à mon sens.

                        C++: Personnellement je perds du temps en C++ à me demander comment organiser mon code, à comprendre du code obscure, à trouver ce que je veux dans la STL, à trouver qu'est ce qui est censé être la bonne façon de faire telle ou telle chose en C++… mais l'utilisation des bibliothèques en C/C++ est facile (gain de temps ici). Je me pose vraiment des questions sur l'intérêt de C++ quand je vois ce qu'il est devenu (ou ce qu'il est resté).

                        Je n'ai pas encore testé Rust, mais à première vue, sa syntaxe tendance minimaliste n'est pas trop mon truc (je préfère plus de verbosité).

                        • [^] # Re: Performance

                          Posté par  (site web personnel) . Évalué à 2. Dernière modification le 09 juin 2019 à 13:09.

                          Ça m'est totalement obscur. Voir ça en 2019 m'a fortement déçu sur l'évolution de C++ et de son écosystème. Et le bout de code en exemple, je l'ai trouvé sur le net

                          J'ai du mal à voir l'obscurité dans ton snippet de code précédent: Tu construis un vector en utilisant deux iterators qui suivent le pattern [begin, end[ que la grosse majorités des API de la STL utilisent.

                          Ton iterator est dans ce cas un simple pointer. Ce sont des features simple du C++, voir même du C.

                          Il n'y a même rien de moderne dans ce snippet, ni C++11, ni C++20. C'est du bon vieux C++98 des familles.

                          Je suis désolé si je suis méchant, mais peut-être est-ce que le problème de base est ton niveau en C++ comparé aux deux autres languages.

                          Un chose que j'admet aisément sur C++, est que l'apprentissage est difficile.

                          La courbe d'apprentissage est non linéaire et implique un gros effort initial, des connaissances du C, du pré-processeur, des phases de compilations du C, des aspects bas niveau du memory management / layout. La phase d'entrée pour être "efficace" en C++ est longue et rebutante pour la plupart des développeurs.

                          A tel point que un de mes critère de recrutement quand j'interview un développeur C++ est comment il se qualifie lui même. Si il se qualifie "d'expert", il est directement disqualifié. Très peu de personnes peuvent se qualifier d'expert, à part certaines personnes du comité C++ lui même.

                          Mais ça ne change rien que pour moi, une fois maitrisé, C++ offre une puissance, une productivité et un écosystème que trés peu de langage peuvent se targer d'avoir. Si ce n'est aucun avec une tel maturité.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 7.

                            J'ai du mal à voir l'obscurité dans ton snippet de code précédent

                            Je pense qu’il ne parle pas du code en soit, mais du contenu de la popup de doc qui est pas franchement user-friendly en effet.

                            • [^] # Re: Performance

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

                              Je pense qu’il ne parle pas du code en soit, mais du contenu de la popup de doc qui est pas franchement user-friendly en effet.

                              Tout à fait. Dans cette popup, je m'attendais plus à y voir une description textuelle accompagnant la signature de fonction, d'autant qu'elle existe.

                              Peut-être est-ce uniquement un problème d'Eclipse (je n'ai pas testé tous les IDE) mais j'espérais qu'une version moderne d'Eclipse soit plus avancée que ça en C++. C'est quand même un gros IDE, et ils ont l'air de mettre le support de C++ pas mal en avant (juste après Java).

                              On va peut-être encore me dire que je suis trop faible en C++ mais lorsque je vais dans la définition du constructeur en question (le même code qu'on voit dans le popup), puis que je fait un ctrl+clic sur la fonction _M_initialize_dispatch pour continuer de naviguer à l'intérieur de la STL, Eclipse m'ouvre une boite de dialogue me demandant de choisir quelle déclaration je veux visiter parmi 4 signatures possibles. Ça commence à se compliquer pour savoir exactement ce qui se passe, puisque c'est au développeur de déterminer le chemin que va prendre le code… (l'IDE semble avoir déjà perdu le fil)

                              Une autre question que je me pose : pourquoi tous ces underscores « _ » (voire double « __ ») partout dans la STL, jusque dans les noms des arguments des fonctions qui sont présentés publiquement ? (__first, __last, __a). Ça fait assez ésotérique et brouille un peu la lisibilité.

                              • [^] # Re: Performance

                                Posté par  . Évalué à 3.

                                mais j'espérais qu'une version moderne d'Eclipse soit plus avancée que ça en C++

                                Eclipse est à la ramasse sur le java par rapport a intelliJ,
                                Eclipse est à la ramasse par rapport à qtCreator, vsCode, et même Clion sur tout ce qui a trait au c++.

                                Eclipse est beaucoup plus lourd que les 4 cités ci-dessus; Par contre, il est multi-langage, et y a une tetrachié de modules

                                Par ailleurs c'est une mauvaise idée de naviguer dans la stl, en tout cas celle de g++, le code est difficilement lisible, et tu pourrais prendre des choses comme acquises qui ne font pas partie de la norme.

                                Si tu veux utiliser la stl, tu vas sur
                                * https://en.cppreference.com/w/
                                * http://www.cplusplus.com/reference/

                                Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                                • [^] # Re: Performance

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

                                  Par ailleurs c'est une mauvaise idée de naviguer dans la stl, en tout cas celle de g++, le code est difficilement lisible, et tu pourrais prendre des choses comme acquises qui ne font pas partie de la norme.

                                  Yep +10.

                                  La STL (et boost ) ne sont clairement pas des exemple en terme de lisibilité.

                        • [^] # Re: Performance

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

                          Je suis aussi un adepte du typage fort. J'ai adoré le Pascal où un prgramme qui compile fonctionne quasiment à coup sûr du premier coup.
                          Vers 1982, j'ai imposé à mes techniciens d'utiliser implicit none dans les programmes en fortran dès que ce fut possible. Ils ont un peu râlé mais nous avons beaucoup réduit le nombre d'erreurs à l'exécution.
                          Je regrette beaucoup de ne pas avoir pu utiliser ADA qui est à mon avis un langage de programmation remarquable, le meilleur à mon avis.

                        • [^] # Re: Performance

                          Posté par  . Évalué à 1.

                          Il y a certaines fonctionnalités que je ne trouve pas alors

                          Tu peux donner des exemples ? car à part l'introspection, j'ai du mal a voir ce qu'il manque par rapport au java (au niveau des capacités du langage)

                          Moi ce qui me manque quand je change de langage (généralement java), c'est la non maitrise des const, impossibilité de choisir entre valeur/référence/pointeur, impossible de redéfinir les opérateurs (simplification d'interface), les template…

                          Ça m'est totalement obscur. Voir ça en 2019 m'a fortement déçu sur l'évolution de C++ et de son écosystème. Et le bout de code en exemple, je l'ai trouvé sur le net. Tout seul je n'aurais pas su l'écrire,

                          Je t'invites a écrire sans aide un appel de java vers c++, ou java vers ada, ou ada vers pascal !

                          Clairement le morceau de code que tu as donné est un interfaçage de C vers C++; et je dirais même un mauvais interfaçage; on récupère un pointeur de pointeurs et on va stocker les pointeurs (probablement des chaine de caractères) dans un vector, le tout sans aucun commentaire sur l'ownership (qui libère quand comment) (ici j'ai l'impression que c'est la bibliothèque qui le fait, mais ça ne dispense pas d'un commentaire); bref, si je suis relecteur de ce code c'est un rejet direct.

                          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                          • [^] # Re: Performance

                            Posté par  . Évalué à 3. Dernière modification le 10 juin 2019 à 09:28.

                            Tu peux donner des exemples ? car à part l'introspection, j'ai du mal a voir ce qu'il manque par rapport au java (au niveau des capacités du langage)

                            Une bibliothèque standard ? Je taquine. Un troll sur les langages le jour de la pentecôte me paraît approprié.

                            • [^] # Re: Performance

                              Posté par  . Évalué à 2.

                              Une bibliothèque standard ?

                              Il y'en a une, si tu veux parler d'une graphique, j'aurais tendance à dire que ce n'est pas le boulot du langage de devoir maintenir une bibliothèque graphique;

                              • il suffit de voir une appli java utilisant les composant de base pour se dire que c'est moche!
                              • il suffit de coder en java sur plusieurs années pour se retrouver avec des morceau noté comme dépréciés
                              • il suffit de coder en java pour se rendre compte que l'interface de swing est dépassée

                              Bref, le coeur du langage doit se concentrer sur les outils de base.

                              Pour le graphique, réseau, xml, Qt fait très bien le taf ;)

                              Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                          • [^] # Re: Performance

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

                            Il y a certaines fonctionnalités que je ne trouve pas alors

                            Tu peux donner des exemples ? car à part l'introspection, j'ai du mal a voir ce qu'il manque par rapport au java (au niveau des capacités du langage)

                            Moi ce qui me manque quand je change de langage (généralement java), c'est la non maitrise des const, impossibilité de choisir entre valeur/référence/pointeur, impossible de redéfinir les opérateurs (simplification d'interface), les template…

                            Quand je parlais des fonctionnalités que je ne trouve pas (ou pas facilement), je pensais à la STL, pas au langage même. Je ne cherche pas à faire de comparaison sur les langages, ils sont différents par définition, mais j'attends pour chacun des langages d'avoir une bibliothèque de base suffisamment fournie et pratique à utiliser.

                            Pour en revenir à un exemple, je cherchais l'autre jour à lire un fichier binaire dans un vector<int>.
                            Le code suivant fonctionne pour un vector<char>, mais pas pour vector<int> :

                            std::ifstream file(filename, std::ios::binary);
                            
                            std::vector<char> buffer(std::istreambuf_iterator<char>(file), {}); // Ok, mais on lit des char...
                            
                            std::vector<int> bufferInt(std::istreambuf_iterator<int>(file), {}); // Ne compile pas

                            Ça m'a un peu étonné de ne pas pouvoir faire ça, pour un langage pourtant si puissant en terme de templates.

                            • [^] # Re: Performance

                              Posté par  . Évalué à 2.

                              pour un fichier binaire j'éviterai d'utiliser int, short ou long mais int32_t, int16_t ou int64_t qui eux te garantissent la taille ;)

                              Ça m'a un peu étonné de ne pas pouvoir faire ça, pour un langage pourtant si puissant en terme de templates.

                              tu peux le faire mais avec le bon itérateur :

                              std::vector<int> bufferInt((std::istream_iterator<int>(file)), std::istream_iterator<int>());
                              
                              // ou 
                              
                              bufferInt.insert(bufferInt.end(), std::istream_iterator<int>(file), std::istream_iterator<int>());

                              Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                • [^] # Re: Performance

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

                  Avec le typage dynamique on a beaucoup plus d'informations de typage au runtime. C'est très utile quand tu fais des programmes configurés par les données par exemple.

                  Le typage dynamique est aussi un cauchemars à tester par sa nature.

                  Car tu n'as aucune garantie que l'objet qui t'est passé a les propriétés nécessaires à l'execution de ta fonction et des N fonctions qui lui sont imbriquées.

                  La seule manière de vérifier ça c'est justement de le tester, là où un typage statique te garantie qu'un object construit d'un type donné a effectivement les propriétés requises.

            • [^] # Re: Performance

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

              Je suis allé voir ta présentation et j'ai remis un œil dans la doc de mypy que je n'avais pas lue depuis très longtemps. Cela à vraiment progressé, c'est vraiment pas mal.

              L'approche des Union est intéressante car elle permet de facilement ajouter / enlever des constructeurs. En contrepartie cela fait des union ouvertes ce qui force à mettre plus de signatures. C'est le sentiment que j'ai avec mypy, il faut mettre des informations de type partout si tu veux que cela fonctionne.

              La documentation me dit que "User-defined generics are a moderatly advanced feature" et cela m'attriste car c'est juste la base du typage (et des trucs amusants). Note: mypy utilise le terme Generic là ou une énorme partie de la littérature utilise le mot polymorphisme.

              Je trouve que beaucoup de choses sont verbeuses, mais c'est principalement une limitation de python qui n'a pas de syntaxe pour faire du pattern matching.

              @dataclass
              class Left(Generic[T]):
                  left: T
              
              
              @dataclass
              class Right(Generic[T]):
                  right: T
              
              either = Union[Left[V], Right[T]]
              
              def tortue(d: T, v : either[T, V]) -> T:
                  if isinstance(v, Left):
                      return v.left
                  else:
                      return d

              Donnerais, en Haskell:

              data Either v t = Left v | Right t
              
              tortue d e = case e of
                 Left v -> v
                 Right _ -> d
              

              Dans le précèdent exemple, je n'ai pas encore réussi à comprendre comment il s'en sort pour affecter V et T à str et int respectivement. L'inférence est assez bonne, je n'arrive à la mettre en défaut que dans quelques rares cas.

              Je n'arrive pas à faire de types calculés ? Par exemple, une fonction type:

              def bar(t1, t2):
                 return ...
              
              
              def foo(a: T1, b: T2) -> bar(T1, T2)
              

              J'ai essayé rapidement sans succès. Avec bar(T1, T2) il refuse et me demande d'utiliser bar[..] et avec cette approche (et bar une instance de class avec __getitem__), il refuse.

              Merci de m'avoir donné envie de donner une nouvelle chance à mypy, cela à fait du progrès. Je le sortirais la prochaine fois que je ferais une intervention chez un client qui refuse de faire du Haskell ;)

          • [^] # Re: Performance

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

            Bah en fait, pas spécialement. Grâce à l'inférence de type dans les bons IDE (et un peu d'aide de temps en temps avec le type hinting), mon code est statiquement typé à 95% (statistique au doigt mouillé, évidemment). Le typage n'est pas vérifié à la compilation (et pour cause) ni au runtime, mais à vrai dire je m'en moque : que ce soit en C++ ou en Python, c'est à l'écriture que j'ai besoin de l'info.
            Je me sers du typage dynamique dans quelques cas (bien bordés) pour simplifier la vie.

            • [^] # Re: Performance

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

              Je me sers du typage dynamique dans quelques cas (bien bordés) pour simplifier la vie.

              Quels cas ? Je suis vraiment curieux. Depuis que je fais du haskell professionnellement, je n'ai jamais eu besoin de typage dynamique.

              Je suis convaincu que des outils comme mypy sont une grosse avancé pour python.

              Si on met de coté tous les autres points de comparaison (c'est arbitraire), quel serait la raison de choisir un langage dynamique par défaut avec du typage optionnel limité vis à vis d'un système statique par défaut, avec un système de type plus développé, mais avec du typage dynamique optionel plus rébarbatif.

              Je n'arrive pas à trouver d'argument en faveur du dynamique par défaut, et pourtant j'essaye.

              • [^] # Re: Performance

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

                Cas très classique avec Django : tu as trois classes qui sont des Model de l'ORM (une classe correspondant à une table SQL avec un attribut pour chaque colonne, une instance correspond à une ligne), qu'on va appeler A, B, C.

                A doit être lié soit à une instance de B, soit à une instance de C (sachant qu'en vrai, ça peut être soit à, B, C, E, F, …).
                En pratique, on a donc deux attributs, un qui indique quelle classe (B ou C) et le second indique la clef primaire au sein de la classe en question.
                Enfin, un a un troisième attribue qui a donc un type dynamique (variable en fonction de l'instance de A) qui sera une instance de B ou C.

                • [^] # Re: Performance

                  Posté par  . Évalué à -1.

                  Autres classiques:

                  1- Je veux des conteneurs de n'importe quel type que je veux pouvoir manipuler en duck typing.

                  l=list([1, "a", {"dudulle":"schmoll"}])

                  Pas d'héritage à la con d'Object avec re-cast (qui ne garantissent rien à la compil du coup), pas d'interface à rajouter à toutes les classes, pas de templating. Bref moins de code pour le prototypage.

                  J'utilise un itérateur pour optimiser la mémoire,… quand je le décide et je réfléchis à une solution plus blindée… quand c'est nécéssaire (Lean).

                  Voilà: 2 lignes vs 200 lignes de code imbitables

                  2- Méta-programmation: Je construis des nouveaux/les types/classes à la volée pour être manipulées par duck typing
                  Le typage statique n'apporte rien au niveau qualité … à part du boilerplate code

                  Ce qu'apporte le typage dynamique ?
                  L'expressivité, la souplesse et la productivité.

                  Ce qu'il enlève ?
                  Lire les autres commentaires

                  Voilà pourquoi on a besoin des 2 !

                  • [^] # Re: Performance

                    Posté par  . Évalué à 2.

                    Je veux des conteneurs de n'importe quel type que je veux pouvoir manipuler en duck typing.
                    […]
                    J'utilise un itérateur pour optimiser la mémoire,… quand je le décide et je réfléchis à une solution plus blindée… quand c'est nécéssaire (Lean).

                    Au risque de me répéter, le duck typing peut se faire tout à fait statiquement, ce n'est absolument pas une nécessité d'avoir recours au typage dynamique pour cela. Ton cas se gère très bien avec les type classes de Haskell.

                    Il en est de même avec l'exemple ORM de flan où il suffit d'utiliser un type somme.

                    J'attends toujours un exemple concret que l'on ne peut pas gérer en typage statique et donc avec perte de sécurité sur le code.

                    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                    • [^] # Re: Performance

                      Posté par  . Évalué à 0.

                      Au risque de me répéter :) A partir du moment où tu fais du duck typing, même en statique, tu n'as plus de contrôle de type.
                      Il n'y a plus de hiérarchie de types. Donc plus de vérification à la compilation… ce qui rend le typage statique caduque pour ce cas, alourdit le code et permet difficilement de concilier les 2 approches.

                      Ce n'est pas pour rien que Go ne supporte que le duck typing, en s'appuyant sur une forme de composition sans le moindre héritage d'implémentation.
                      Avec Python, on concilie le duck typing avec l'héritage multiple, ce qui d'ailleurs permet de se passer de la généricité.

                      Par contre, j'attends l'exemple dans un langage statiquement typé orienté objet (donc pas le Go) qui permet de se passer de l'héritage du type racine et du casting à posteriori.
                      Un truc quasi-quotidien dans les langages dynamiques.

                      • [^] # Re: Performance

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

                        Par contre, j'attends l'exemple dans un langage statiquement typé orienté objet (donc pas le Go) qui permet de se passer de l'héritage du type racine et du casting à posteriori.
                        Un truc quasi-quotidien dans les langages dynamiques.

                        En OCaml

                        let duck = object
                          method talk = "quack"
                        end
                        
                        let cow = object
                          method talk = "mooh"
                        end
                        
                        let talk animal = animal#talk
                        
                        talk duck;;
                        - : string = "quack"
                        
                        talk cow;; 
                        - : string = "mooh"
                        • [^] # Re: Performance

                          Posté par  . Évalué à 1.

                          Ca c'est du structural typing, non ? J'avoue que la syntaxe est tellement absconse que je pige pas tout le bout de code.

                          https://en.wikipedia.org/wiki/Duck_typing

                          Duck typing is similar to, but distinct from structural typing. Structural typing is a static typing system that determines type compatibility and equivalence by a type's structure, whereas duck typing is dynamic and determines type compatibility by only that part of a type's structure that is accessed during run time.

                          The OCaml, Scala, Go, Elm,[4], Gosu and PureScript languages support structural typing to varying degrees.

                          Comme je pige pas tout, tu dois tout de même "statiquement" associer ce sous-ensemble de méthodes si je saisis bien.

                          Je conviens cependant que c'est déjà plus intéressant (et peut-être suffisant, à creuser) que ce que propose les langages OO statiquement typés mainstream. Java, C# et C++ par exemple. C'est drôlement handicapant.
                          Un peu moins de verbosité, de lisibilité et on y est peut-être. Je vois que Scala est dans la liste. Je vais peut-être l'explorer du coup.

                          Question naïve (pas de piège):
                          Pourquoi OCaml reste si confidentiel s'il est si génial ?

                          • [^] # Re: Performance

                            Posté par  . Évalué à 4.

                            Ca c'est du structural typing, non ? J'avoue que la syntaxe est tellement absconse que je pige pas tout le bout de code.

                            Non c'est bien du duck typing, mais les auteurs de la page wikipédia ont écrit n'importe quoi.
                            Pour la syntaxe absconse, c'est juste une question d'habitude sur le let binding. Pour définir une varibale, comme un entier, on écrit let i = 1 c'est-à-dire soit i l'entier 1 ou en anglais let i be the integer 1.

                            Pour reprendre les exemples de la page wikipédia :

                            class duck = object
                              method fly () = print_endline "Duck flying"
                            end
                            
                            class airplane = object
                              method fly () = print_endline "Airplane flying"
                            end
                            
                            class whale = object
                              method swim () = print_endline "Whale swimming"
                            end

                            Pour savoir si un objet peut voler, c'est bien du duck typing :

                            let fly o = o#fly ();;
                            val fly : < fly : unit -> 'a; .. > -> 'a = <fun>

                            la notation o#fly () consiste à appeler la méthode fly de l'objet o, et l'inférence de type conclue que pour utiliser la fonction fly sur un objet o celui-ci doit posséder une méthode fly et possiblement d'autres méthodes (les ... dans le type de l'objet). Ainsi :

                            fly (new duck);;
                            Duck flying
                            - : unit = ()
                            
                            fly (new airplane);;
                            Airplane flying
                            - : unit = ()
                            
                            fly (new whale);;
                            Error: This expression has type whale but an expression was expected of type
                                     < fly : unit -> 'a; .. >
                                   The first object type has no method fly

                            L'erreur est détectée statiquement.

                            Pourquoi OCaml reste si confidentiel s'il est si génial ?

                            Je n'ai pas la réponse à la question. Peut être parce que c'est un langage académique et qu'il n'a pas la force de frappe en communication d'entreprises comme Google ou Oracle. Mais cela va peut être changer maintenant que facebook s'y est mis, bien qu'il le fasse via le langage Reason (qui n'est rien d'autre qu'une syntaxe concrète différente pour du OCaml afin qu'il ressemble plus au javascript : c'est laid, mais apparemment cela désarçonne moins leur cible de développeurs).

                            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                      • [^] # Re: Performance

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

                        Au risque de me répéter :) A partir du moment où tu fais du duck typing, même en statique, tu n'as plus de contrôle de type.

                        Si. A un moment, tu vas utiliser ton objet et tu va vouloir une interface "commune", sinon tu ne peux rien faire.

                        Si j'ai une liste python [True, "hello", 10, [1,2,3]], c'est très bien, mais je peux faire quoi avec? Seulement des choses commune à tous ces types, comme, dans ce cas, les convertir avec str:

                        for i in [True, "hello", 10, [1,2,3]]:
                           print(str(i))

                        A partir de ce moment là tu as donc une définition de type qui, en Haskell par exemple, serait un Show t => t, ou dit autrement: n'importe quel type t qui respecte la contrainte Show.

                    • [^] # Re: Performance

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

                      Mais comment fais-tu ton type somme si tu ne sais pas quels sont les sous-types de ce type somme ?
                      Potentiellement, le code des classes D, E, F… sont créées de façon indépendante, sans que le code principal contenant A et B ne soit modifié (mettons que F est fournie par un plugin tierce-partie, qui ne peut pas modifier A).

                      • [^] # Re: Performance

                        Posté par  . Évalué à 2.

                        Mais comment fais-tu ton type somme si tu ne sais pas quels sont les sous-types de ce type somme ?

                        Là il me faudrait un exemple pour mieux comprendre la situation. Tu peux illustrer avec un code minimal en python la situation que tu as en tête : pas besoins d'implémenter les méthodes, un pass suffit; je veux juste avoir une idée plus claire et précise de l'architecture globale du code.

                        Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                        • [^] # Re: Performance

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

                          Dans le code principal.
                          Avec un ORM, on aura donc une équivalence classe <=> table SQL, et instance <=> ligne de la table.

                          >>> class A:
                          >>>   owner_type_id = CharField("module.class") # ou tout autre identifiant de classe ORM
                          >>>   owner_id = IntegerField() #  clef primaire de l'objet en question
                          >>>   
                          >>>   def owner(self):
                          >>>     return self.owner_type_id.get_by_id(self.owner_id) 
                          
                          
                          >>> owner_1 = B()  # instance quelconque de l'ORM
                          
                          >>> instance = A(owner_type_id=owner_1.__class__, owner_id=owner_1.id)
                          
                          >>> instance.owner == owner_1
                          True

                          La classe B (ou C, D, …) n'a à aucun moment besoin d'être connu du code de A, ce qui est bien pratique s'ils sont dans des plugins codés par d'autres entités.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 4. Dernière modification le 07 juin 2019 à 00:42.

                            Je ne suis pas bien sûr de comprendre tout ton code, mais ça m'a tout l'air d'être juste une question de généricité. Si je comprends bien, l'attribut owner_typ_id de ton instance est la classe de owner_1. Ta classe A est juste une classe paramétrée et effectivement elle n'a pas besoin de connaître toutes les classes B, C, D… Tu peux voir cela comme un type somme infini, si tu veux. Par exemple, le type paramétré List <T> peut être pensé comme List <Int> ou List <Float> ou List <String> ....

                            Peut être qu'ici, comme le paramètre de type ne peux pas être quelconque (il doit disposer de certaines méthodes, comme get_by_id), il faudrait utiliser des GADT pour restreindre les valeurs possibles du paramètres de type; mais rien qui ne me semble inaccessible au typage statique.

                            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                          • [^] # Re: Performance

                            Posté par  . Évalué à 2.

                            J'ai répondu un peu vite hier, mais plus qu'un type paramétré, ton histoire ressemble à une classe paramétrée par d'autres classes. Dans le jargon des langages ML, on appelle cela des foncteurs : des modules paramétrés par d'autres modules, c'est-à-dire des fonctions des modules dans les modules. Les types paramétriques sont des foncteurs, mais tous les foncteurs de sont pas des types paramétriques (comme les canards sont des animaux, mais les animaux ne sont pas tous des canards).

                            Pour comprendre un peu ce qu'est un module, prenons cette classe python :

                            class a:
                                 def __init__(self, i):
                                     self.attr = i
                                 def get_attr(self):
                                     return self.attr

                            Dans les langages de la famille ML, on n'utilisera pas de classe pour exprimer cela mais un module :

                            module A : sig 
                              type 'a t
                              val init : 'a -> 'a t
                              val get_attr : 'a t -> 'a
                            end = struct
                              type 'a t = 'a
                              let init i = i
                              let get_attr x = x
                            end

                            Le problème général du paradigme objet est qu'il confond (de manière totalement ridicule) un concept avec une théorie sur un concept donné. Ici le concept (qui est générique) c'est le type paramétrique A.t et les autres fonctions du modules forment une théorie sur ce concept. Du point du vue du paradigme objet, on se met à dire que c'est la théorie sur A.t, soit le module A, qui définit le concept : c'est inepte. On peut tout à fait étendre la théorie (rajouter des fonctions) sans changer le moins du monde le concept dont elle parle.

                            Là où cela devient gênant en général, c'est quand on pratique l'héritage. On a coutume de dire, dans le monde de l'orienté objet, que comme un canard est un animal alors la classe canard hérite de la classe animale : c'est faux et absolument faux. La proposition les canards sont des animaux signifie que les canards sont un sous-type (et non une sous-classe) du type animal. Il est rare que des les deux notions de sous-classe et de sous-type se recouvre, en particulier ça ne marche plus dès qu'il y a des opérateurs binaires.

                            Quittons cette digression sur le monde objet, et revenons à nos modules. Je disais plus haut que les types paramétriques sont des foncteurs, voyons cela avec le type générique des listes.

                            (* on plonge les types dans le monde des modules *)
                            module type T = sig type t end
                            
                            (* le type des listes est un foncteur *)
                            module ListF (A : T) = struct type t = A.t list end;;
                            module ListF : functor (A : T) -> sig type t = A.t list end
                            
                            (* illustration sur les listes d'entiers *)
                            module Int_list = ListF (struct type t = int end);;
                            module Int_list : sig type t = int list end
                            
                            (* pas de problèmes de typage *)
                            ([1; 2; 3] : int_list);;
                            - : int_list = [1; 2; 3]
                            
                            ([1; 2; 3] : Int_list.t);;
                            - : Int_list.t = [1; 2; 3]

                            Maintenant si on veut que notre module paramétré (notre foncteur) n'opère par sur n'importe quel type mais sur des types munis de certaines opérations, on le précise par une contrainte de types sur la signature du paramètres.

                            (* les contraintes de type sur le paramètre *)
                            module type S = sig
                              type t
                              val of_string : string -> t
                              val meth : t -> int
                            end
                            
                            (* notre module paramétré *)
                            module A (M : S) = struct
                              type owner = M.t
                              let f () = M.(meth (of_string "foo"))
                            end

                            Voilà : A ne connaît absolument rien des modules qui lui seront passés en paramètre si ce n'est qu'ils doivent satisfaire les contraintes de la signature S.

                            On peut définir ensuite plus loin, dans d'autres entités, des modules à lui passer.

                            module M : S = struct
                              type t = string
                              let of_string x = x
                              let meth = String.length
                            end
                            
                            module N : S = struct
                              type t = int
                              let of_string s = try int_of_string s with _ -> 0
                              let meth i = i
                            end
                            
                            module B = A (M)
                            module C = A (N);;
                            (* note la valeur des types [owner] dans chacune des applications *)
                            module B : sig type owner = M.t val f : unit -> int end
                            module C : sig type owner = N.t val f : unit -> int end
                            
                            (* application de [f] pour les modules résultants *)
                            B.f ();;
                            - : int = 3
                            
                            C.f ();;
                            - : int = 0

                            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

                  • [^] # Re: Performance

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

                    Voilà pourquoi on a besoin des 2 !

                    Oui ! Mon interrogation dans ce débat c'est de savoir si il est mieux d'avoir un typage statique par défaut avec du dynamique optionnel, ou l'inverse.

                    l=list([1, "a", {"dudulle":"schmoll"}])

                    Et tu fais souvent cela ? Je vois cet exemple tous le temps, mais qui fait vraiment ça ?

                    Je construis des nouveaux/les types/classes à la volée pour être manipulées par duck typing

                    Je veux bien un exemple aussi.

        • [^] # Re: Performance

          Posté par  (site web personnel) . Évalué à 5. Dernière modification le 05 juin 2019 à 10:41.

          Désolé, mais je désapprouve un peu prés tous les arguments que tu avances

          ton application C++ en 30ans tu l'a réécrite 2 fois au moins (une fois pour prendre en compte C++98 et une pour C++11) si tu t'en es bien sorti. Oui tu as aussi dû réécrire ton application python pour passer à python3 on est d'accord. C'est juste pour dire que la maintenance de ce genre de code même en C++ ce n'est pas trivial du tout.

          En pratique tu ne fais jamais ça. Sauf si ton software lead est incompétent.

          C++20 est toujours compatible avec C++98, tu ne réécris pas pour le plaisir de réécrire. Tu migres lentement la code-base pièce par pièce en utilisant les nouvelles fonctionnalités du C++ moderne quand requises.

          Certaines code-base C++ dépasse plusieurs millions de ligne de code, ré-écrire ça tous les 6 mois est impensable.

          il est beaucoup plus simple d'écrire des tests, mais vraiment beaucoup. Le duck typing (ou le typage structurel) est un bonheur pour ça

          Boost.UnitTest ou Catch2 permet d'écrire des tests en 5 lignes de code.
          Les templates te permettent de généraliser tes testes automatiquement à N types si nécessaire.

          Le duck typing n'apporte rien ici, le duck typing et le typage dynamique ont généralement l'effet inverse. Ils rendent nécessaires des batteries de testes larges et complexes pour gérer le large eventail d'input / possibilité que le duck typing autorise sur ton code et tes fonctions.

          il existe un outillage autour de python beaucoup plus riche que pour C++.

          5 ans en arrière j'aurai dit oui. Aujoud'hui je dis non.

          C++ a maintenant ses lintians, C++ a ses analyseurs statiques (plus puissants que en python car typage statique), C++ a ses auto-formateurs, remote-debugger, sanitizer, etc etc.

          L'ecosystème n'a plus grand chose à envier à python si ce n'est son propre package manager, qui comme je l'ai déja dit X fois ici est une fausse bonne idée.

          • [^] # Re: Performance

            Posté par  . Évalué à 3.

            C++20 est toujours compatible avec C++98, tu ne réécris pas pour le plaisir de réécrire. Tu migres lentement la code-base pièce par pièce en utilisant les nouvelles fonctionnalités du C++ moderne quand requises.

            C'est ce que j'appelle une réécriture. J'ai pas dis que c'était fais d'un bloc. Je dis que tu es passé partout pour passer ton code de C++ non normalisé à C++98 puis de C++98 à C++11. Tu as eu un travail spécifique de montée de version de ton code. Et c'est pas une critique c'est normal. C'est juste que quand on vient me dire qu'une base de code est maintenu depuis 30 ans, le maintiens d'une base de code ça consiste à la faire évoluer qu'il a fallu prendre en compte au moins C++98 et C++11 etc.

            Boost.UnitTest ou Catch2 permet d'écrire des tests en 5 lignes de code.

            Je n'ai même pas besoin d'aller voir ce qu'ils font exactement pour savoir qu'on ne parle pas de la même chose. Avoir un runtime de test c'est un premier point, mais il y a un paquet d'autres choses qui peuvent aider :

            • une bibliothèque de mock, ne pas dépendre d'une base de données ou d'un brocker de message pour exécuter tes tests est très utile
            • une bibliothèque de génération de données, ça permet de construire bien plus rapidement les inputs de tes tests. nbuilder du monde .Net ou faker.js sont pas mal pour ça
            • avoir une bibliothèque d'assertions ce qui permet de se rapprocher de test de propriétés (de tester des nombres à virgules flottantes, du temps, des structures complexes,…).

            Après le runtime de tests peut aussi servir à créer des tests suites et de faire des tests paramétrés, générer des rapports pour des outils comme sonarqube.

            De ce que j'en vois Boost.UnitTest et Catch2 font des choses bien, mais ils sont loin de faire toutes ces choses.

            Le duck typing n'apporte rien ici, le duck typing et le typage dynamique ont généralement l'effet inverse. Ils rendent nécessaires des batteries de testes larges et complexes pour gérer le large eventail d'input / possibilité que le duck typing autorise sur ton code et tes fonctions.

            Le duck typing consiste a vérifier que la référence que l'on te donne possède les propriétés nécessaires à ce que tu en fais. C'est le typage dynamique qui rend la chose plus difficile. Mais c'est clairement une aide au mocking.

            5 ans en arrière j'aurai dit oui. Aujoud'hui je dis non.

            Oui ça aura mis du temps à arrivé, mais la situation s'est bien amélioré. Je l'ai découvert ici en discutant.

      • [^] # Re: Performance

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

        Python est fait pour faire du prototypage rapide avec du code qui finira difficilement
        maintenable due à son typage dynamique et ses performances.

        D'ailleurs ironiquement python et ses modules sont principalement fait en C et C++

        Sur les performances, tu te contredis toi même. Oui beaucoup de modules python sont en fait du code C/C++ donc pas de baisse de performances à prévoir…

        Bien sûr par contre, si tu comptes faire du traitement d'image en pur python sans passer par pillow, ça va pas le faire niveau perf.

        • [^] # Re: Performance

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

          Sur les performances, tu te contredis toi même. Oui beaucoup de modules python sont en fait du code C/C++ donc pas de baisse de performances à prévoir…

          Absoluement pas, car dans ce scénario tu fais du développement C/C++ un pré-requis au développement python pour les parties perf critical. Qui suivant ton secteur, peuvent arriver trés rapidement.

          • [^] # Re: Performance

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

            Absoluement pas, car dans ce scénario tu fais du développement C/C++ un pré-requis au développement python pour les parties perf critical. Qui suivant ton secteur, peuvent arriver trés rapidement.

            Performance, ça reste un terme très générique. De quelles performances on parle réellement ?

            1. D'avoir le plus petit runtime en mémoire ? Python est clairement un mauvais candidat, comme tous les langages interprétés et tous les langages à VM.

            2. De faire des gros calculs numériques ? Python est très très bien équipé avec pandas, numpy, pytorch et autres projets de calcul scientifique. Ces projets sont écrits en C/C++, leur utilisation en Python te permet donc de bénéficier des perf d'une implémentation native. Il faut vraiment avoir besoin de calculs haute performance très très spécifiques pour tomber en dehors des service fournies par l'écosystème déjà présent.

            3. De faire beaucoup de processing io-bound ? Python s'en sort aussi très bien, en particulier avec les apports des modes asynchrones des dernières versions.

            4. De faire beaucoup de processing cpu-bound ? Clairement, Python n'est pas le meilleur candidat mais c'est quand même assez rare d'avoir des jobs cpu-bound pour lesquels il n'existe pas d'implémentation native.

            5. De faire une interface graphique réactive ? Je fais régulièrement du Python avec PyQt et mes interfaces sont très réactives. Par exemple, j'ai utilisé récemment une vue sur des tableaux de plusieurs dizaines de milliers d'items sans problème visible.

            6. De fournir un produit fonctionnel à un client à un coût moindre ? Python, avec sa rapidité de développement et l'immense bibliothèque de package disponible est certainement un candidat intéressant à considérer.

            La soi-disant lenteur de Python est un vieux mythe qui continue de planer, déconnecté des réalités. Python est moins rapide que d'autres langages pour certaines tâches très précises, mais pour la majorité des programmes qui sont écrits, il est tout à fait suffisant.

            Petite anecdote, j'ai participé à la "battle dev" ( https://battledev.blogdumoderateur.com/ ) sous le nom de ma boite et certains collègues habitués au C/C++ ont été choqués qu'on puisse résoudre la plupart des problèmes en Python, alors même qu'ils nécessitaient pas mal de calcul et de parcours de structures de données.

            • [^] # Re: Performance

              Posté par  . Évalué à 1.

              Python s'en sort aussi très bien, en particulier avec les apports des modes asynchrones des dernières versions.

              Sans compter les green threads (Gevent) qui avec un petit monkeypatch et 2 lignes de code te transforment un code séquentiel en asynchrone gratis.
              Même pas besoin de te lancer dans un gros refactoring pour tout passer en asynchrone explicite.

            • [^] # Re: Performance

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

              De faire des gros calculs numériques ? Python est très très bien équipé avec pandas, numpy, pytorch et autres projets de calcul scientifique. Ces projets sont écrits en C/C++, leur utilisation en Python te permet donc de bénéficier des perf d'une implémentation native. Il faut vraiment avoir besoin de calculs haute performance très très spécifiques pour tomber en dehors des service fournies par l'écosystème déjà présent.

              Encore une fois tu confirmes ce que je dis. Tes performances "correcte" en python tu ne les a que parce que un bon gars est passé par la avant toi et a fait un module python en C++ qui va bien pour traiter ce cas d'utilisation en pybind11, boost.python ou autre.

              Le python tu ne l'utilises que pour scripter au dessus de ça, et c'est trés bien.

              • [^] # Re: Performance

                Posté par  . Évalué à 2.

                Ça peut être posé à l'opposé pourquoi écrire un projet en C++ aujourd'hui, plutôt qu'en python et ne coder que la partie qui prend de la puissance de calcul/mémoire en C++ ?

                • [^] # Re: Performance

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

                  Ça peut être posé à l'opposé pourquoi écrire un projet en C++ aujourd'hui, plutôt qu'en python et ne coder que la partie qui prend de la puissance de calcul/mémoire en C++ ?

                  C'est ce que fait une grande partie du monde du calcul scientifique et de l'artificial intelligence à l'heure actuelle ( tensorflow, pytorch ). C'est une approche valide pour certains champs d'utilisations.

                  Pour d'autres cas d'utilisation plus orienté "système" : coder une database, un broker, un FS, un game engine, un service lourd système à faible latence, forte charge. Le python apporte plus d'inconvenient qu'ils n'apportent d'avantages, à mon humble avis.

                  • [^] # Re: Performance

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

                    Tes exemples sont tout à fait pertinents sur des trucs qu'il ne vaut mieux pas faire en Python. En même temps, je suis sûr que tu seras d'accord pour reconnaitre que parmi tout le code qui est écrit dans une semaine aujourd'hui dans le monde entier, la proportion qui concerne les exemples que tu cites est extrêmement infime. Et en dehors de ces cas précis, Python s'avère un langage où les performances sont largement suffisante pour les besoins de ses utilisateurs.

                    Mon expérience n'est pas universelle mais je peux quand même la partager: depuis 18 ans que je fais du Python, je n'ai fait du profiling pour accélerer mes programmes que 3 fois. Et une fois, j'ai renoncé à écrire un programme (un clone de vi en Python) parce que Python était trop lent. Mais je devais avoir un problème de design car SublimeText y arrive très bien.

                    D'un autre côté, mon boulot quotidien est d'écrire du code pour des cartes à puce, donc de l'embarqué contraint en vitesse, en taille de code et très fortement contraint en sécurité. On ne fera jamais de Python là-dedans très clairement, seul le langage natif de le puce est approprié (en mélange C / ASM).

                    • [^] # Re: Performance

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

                      D'un autre côté, mon boulot quotidien est d'écrire du code pour des cartes à puce, donc de l'embarqué contraint en vitesse, en taille de code et très fortement contraint en sécurité. On ne fera jamais de Python là-dedans très clairement, seul le langage natif de le puce est approprié (en mélange C / ASM).

                      Pour le coup nous on fait du Haskell pour ce type de problématique. Le Haskell génère du C, mais avec des garanties et plus de généricité.

                      Ceci étant dis, je suis tout à fait d'accord avec toi sur le point performance de Python. C'est très souvent surfait et bien souvent Python est suffisamment performant pour beaucoup de cas.

  • # Go ou Rust?

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

    Pourquoi partir sur du Python et pas sur un langage performant?

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Go ou Rust?

      Posté par  . Évalué à 8.

      La notion de performance est assez subjective et dépend de ton objectif.

      Python est très performant… pour sortir quelque chose de fonctionnel rapidement. Par contre en effet, le code n'ira pas forcément très vite, et encore, tu as de tels outils en python que les parties critiques seront elles bien optimisées, potentiellement avec de bien meilleurs algos que ce que tu aurais utilisé dans un langage plus complexe. En pratique le dev c'est quand même énormément de glue et de scotch.

      Bref, avant de choisir le langage, faut se demander pour quelle utilisation avec quel budget, le client est souvent prêt à perdre quelques millisecondes de CPU à la requête contre quelques mois de développement.

      • [^] # Re: Go ou Rust?

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

        Le client est souvent prêt à perdre quelques millisecondes de CPU à la requête contre quelques mois de développement.

        D'après mon expérience dans le monde professionnel, c'est généralement le cas. A part mon stage de fin d'étude qui était dans un domaine bien spécifique (la robotique), je n'ai jamais rencontré de client pour qui la performance était primordiale. Ils veulent tous un code qui fonctionne, avec des retours les plus nombreux et les plus rapides possibles. Si c'est (vraiment) trop lent, on change de matériel, et c'est bon.

        On peut regretter cet état des faits, mais dans le monde réel, c'est très souvent comme ça.

        • [^] # Re: Go ou Rust?

          Posté par  . Évalué à 5.

          Il faut quand même se préparer à un changement sur ce point avec l'arrivée de green IT. Parce qu'utiliser un langage peu performant qui consomme des cycles CPU (donc de l'energie) pour rien, c'est pas très écolo.

          Alors je ne sais pas si green IT c'est juste un truc a la mode ou si ça va réellement prendre un jour, mais si ça prend, il va falloir penser à revoir certaines archis, et à revoir les habitudes de développement du style "si ça rame, on change de matos".

          Après je suis peut-être pessimiste, mais j'ai l'impression que l'ère du hardware pas cher va bientôt cesser. Exemple: le prix de la RAM qui a flambé depuis quelques années suite à la pénurie liée aux besoins de RAM pour les smartphones. Le fait que ce atériel est conçu avec des matériaux rares, n'arrange pas les choses (combien de temps pourrons-nous tenir le rythme actuel). Ces matériaux sont semble-t-il détenus en grande partie par la Chine (je crois avoir lu qu'elle en possédait environs la moitié), et la guerre commerciale US-Chine risque de ne pas arranger les choses.

          Donc je pense que dans peu de temps, les devs capable d'écrire des programmes consommant peu de ressources (hardware et énergie) seront de plus en plus recherchés.

          • [^] # Re: Go ou Rust?

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

            Parce qu'utiliser un langage peu performant qui consomme des cycles CPU (donc de l'energie) pour rien, c'est pas très écolo.

            À mon avis c'est surtout consommer des cycles CPU pour des applications qui servent à pas grand chose qui n'est pas très écolo ;-)

            • [^] # Re: Go ou Rust?

              Posté par  . Évalué à 0.

              Bof faut voir, ça sediscute …
              Une application qui ne sert pas a grand chose ne sera pas forcément très sollicitée, donc ne consommera pas tant de cycle CPU que ça. En tout cas, moins qu'une application beaucoup utilisée, qui consomme beaucoup de cycle CPU dans tous les cas, mais qui en consomme encore plus parce que le langage ou le framework sur lequel elle a été développé en a rajouté encore plus.

      • [^] # Re: Go ou Rust?

        Posté par  (site web personnel) . Évalué à 7. Dernière modification le 03 juin 2019 à 14:44.

        J'entendais la performance de l'application à l'exécution puisque cela est évoqué dans le journal:

        En C++, le développement est lent, mais l’application est très rapide ;
        En Python, le développement est rapide, mais l’application est très lente.

        Je n'ai pas encore eu le temps de tester Rust à fond, mais en Go le développement est au moins aussi rapide qu'en Python.

        Sauf bibliothèque qui ferait exactement ce que tu veux en Python pour ton domaine précis, je ne vois aucun avantage compétitif à ce dernier en général.

        Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

        • [^] # Re: Go ou Rust?

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

          Il faut passer pas mal de temps à faire du Rust avant d'être efficace, mais je trouve qu'on code très rapidement. Moins qu'en Python, ceci dit. Le grand avantage, c'est qu'on n'a pas d'erreur au runtime, donc on gagne du temps là-dessus.

          • [^] # Re: Go ou Rust?

            Posté par  . Évalué à 5.

            Le grand avantage, c'est qu'on n'a pas d'erreur au runtime, donc on gagne du temps là-dessus.

            Je pense que tu as mis le doigt sur la grande différence entre les deux méthodes de développement.

            En Rust par exemple, tu vois un tas de problème en amont, qui certes te ralentissent un peu pour fournir une fonctionnalité, mais d'un autre côté, quand tu fournis cette fonctionnalité, tu sais que tu t'évites un tas de bugs. D'un autre tu peux fournir un truc rapide mais il va certainement devoir revenir dessus pour fiabiliser le code. Je ne suis pas sur qu'au final, développer en RUST te fgasse perdre tant de temps que ça.

          • [^] # Re: Go ou Rust?

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

            Il y a tout de même des outils pour vraiment améliorer la situation en Python. Un bon IDE va faire de l'inférence de type et tu n'auras à peu près jamais d'erreur de type au runtime.

            • [^] # Re: Go ou Rust?

              Posté par  . Évalué à 0.

              Bof il n'y a pas que les erreurs de typage qui posent problème. Il y en a bien d'autres que Rust permet de compenser. Et ce que je dis pour python/rust est valable aussi pour C/rust par exemple.

              • [^] # Re: Go ou Rust?

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

                Non, bien sûr, c'est sûr que Rust apporte bien plus de garantie.
                Simplement, à partir du moment où tu utilises les bons outils, les bugs triviaux (comme les erreurs de type) n'existent plus, ou presque.

        • [^] # Re: Go ou Rust?

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

          Sauf bibliothèque qui ferait exactement ce que tu veux en Python pour ton domaine précis, je ne vois aucun avantage compétitif à ce dernier en général.

          Par rapport à du Go, Python propose une REPL (un shell interactif quoi) qui amène beaucoup de convivialité:
          - Dès que tu as un doute sur une construction tu peux tester, ça rend plus aventureux ;-)
          - Tu peux interagir avec une lib dont tu ne connais pas/mal l'api plutôt que d'avoir uniquement la doc. C'est incroyablement pratique quand on tâtonne pour faire un truc en particulier.
          - Pareil pour le débug dans lequel tu as vraiment une puissance d'introspection énorme qui aide à comprendre ce qui se passe (voir à modifier/monkeypatch tout à la volée pour vérifier que ton intuition est la bonne)
          - Pour une application interagissant avec une base de donnée, tu as quasiment gratuitement un shell avec une couche métier (en exposant les classes de ton ORM) qui te permet de manipuler les données facilement

          • [^] # Re: Go ou Rust?

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

            Il y a des REPL en Go (gore, gosh) et le tout simple go run hello-world.go.

            Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

      • [^] # Re: Go ou Rust?

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

        J'aurais même tendance à dire qu'il est souvent bien plus rentable de rajouter une machine ou deux plutôt que d'ajouter le temps de développement. Un mois de développement supplémentaire doit coûter dans les 5 000€ minimum à l'employeur, le serveur de plus est vite rentabilisé si on développe vraiment plus vite.

        • [^] # Re: Go ou Rust?

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

          C'est vraiment le strict minimum. Là où je bosse, ils ont surtout des prestataires, c'est dans les 12k€ par mois pour un développeur. C'est clair qu'une mise-à-jour du matériel est moins chère.

          • [^] # Re: Go ou Rust?

            Posté par  . Évalué à 5. Dernière modification le 04 juin 2019 à 12:02.

            Yep, c'est ce qui se disais aussi ici, le temps d'exec on s'en fout, sauf qu'on a passé la limite critique de temps de calculs, notamment pour la coordination européenne, les gens ont tellement codé comme des porcs, qu'en à peine 1 journée de boulot, on est passé de 1h de traitement à 30 minutes, un calcul mal placé. Mais régulièrement on fait 2 ou 3 recherche dans les map, là où une seule suffit.

            Les gens oublient que le insert en c++ n'insert rien si l'objet est déjà présent (et renvoi une paire (itérateur de l'élément dans la map (nouveau ou ancien), booleen d'insertion), et font des recherche/ajout,

            Alors ce genre de petits détails peut ne pas impacter l'appli, quand tu les fais en plein milieu des calculs ça commence à impacter sérieusement les perfs. De même utiliser un vector pour une liste d'éléments dans laquelle on supprime et ajoute des éléments n'est pas non plus optimal.

            Je ne parle même pas des allocations dynamique là où une variable locale suffit.

            C'est clair qu'une mise-à-jour du matériel est moins chère.

            Yep c'est ce que le client pensait aussi, sauf qu'en codant avec des complexité en O(K * N²), le K a 3 ou 4 il commence à faire mal lors des calculs intensifs; si à cela tu ajoute que souvent on est en n3 au et que pas mal de n² pourraient être en n * log(n), le coût du matériel commence à se faire vraiment sentir, et qui dit serveur de plus (on fait du calcul distribué), dit aussi maintenance en plus.

            Y'a quelques années j'avais aussi gagné un facteur 3 sur un ensemble de calculs (une bonne semaine de boulot, factorisation des calculs identique)

            Bref optimiser à fond, traquer le point qui fait perdre 3ms, aucun intérêt; par contre timer le code voir où on perd le plus de temps, voir si c'est normal, et dans le cas contraire s'en occuper est indispensable.

            Plus récemment, j'ai trouvé dans le code une recherche d'élément dans une map qui ne cherche pas par la clé (problème de jouer avec plusieurs identifiants); le tout dans uns boucle, schématiquement c'est

            for( auto pika : lstElement )
            {
              if ( grosConteneur.getFromSecondary(pika)   // O(n)
                   ||  grosConteneur.get(pika)  )         // O(log(n)) 
              {
                 Choux bruxelle = grosConteneur.getFromSecondary(pika);
                 if( !bruxelle )
                   bruxelle = grosConteneur.get(pika);
                 [...]
              }
            }

            Le stict minimum, c'est d'avoir une durée qui n'explose pas dès qu'on augment un peu la volumétrie; sinon c'est tous les 2 mois qu'il faut racheter des serveurs, multiplie ça par le nombre de lieu où c'est déployé (5-6 en France, et d'autre à l'étranger), l'achat de serveur n'est pas toujours la bonne solution.

            Il ne faut pas décorner les boeufs avant d'avoir semé le vent

  • # Mon avis (professionnel)

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

    Je suis aussi fou du C++ (presque juriste). J'en ai d'abord fait personnellement puis j'ai commencé à être développeur professionnel. Dès ma première expérience, j'ai vite déchanté. Je suis tombé sur une équipe sympathique mais ne connaissant rien des nouvelles normes (C++11, on était en 2013 à cette époque) donc j'ai du tout leur apprendre et j'ai commencé à faire des présentations du C++ moderne. J'ai fait ça à mon entreprise, à une école, un LUG, etc. Même après ça, mon équipe continuait de faire du C++98 ou autres idioms désuets ce qui a commencé à m'attrister, étant personnellement extrêmement exigeant.

    J'ai quitté cette entreprise au bout de 3 ans et rejoint plusieurs autres et je me suis rendu compte que c'était malheureusent partout pareil. Peu de gens s'intéressaient à la nouveauté, certains me le disaient explicitement « j'avoue, je n'ai pas regardé les nouveautés ». Donc avec le temps j'ai commencé à beaucoup déprimer à force de travailler avec des personnes ne souhaitant pas se mettre à jour. C'est simple, j'ai jamais trouvé quelqu'un plus fort que moi en C++ (en entreprise j'entends bien). Et n'allez pas croire que je me vante, c'est juste un fait objectif. À chaque fois que j'apprends une nouvelle chose simple à un collègue, on me répond « je connaissais pas ». Notez aussi, j'ai jamais fait une seule ligne de C++ dans mon cursus universitaire ; c'est bien parce que je suis passionné et curieux que j'ai pu accumuler toutes ces connaissances sur le C++. Pour faire simple, le C++17 n'était pas finalisé que je connaissais tous les changements apportés.

    Pour en revenir à ma situation professionnelle, j'ai l'impression que selon les langages on peut être vite déçu si l'on est très exigeant comme moi. Et personnellement ça me fatigue et me donne envie d'une reconversion professionnelle totale. Car en réalité, j'aime coder pour moi sans avoir à faire à une quelconque autre personne venant interférer mon code dès lors qu'il ne me ressemble pas. Et à l'heure actuelle, quand je rentre chez moi le soir je n'allume même plus mon ordinateur pour coder mes projets libres perso que j'aime. Et c'est pas faute d'avoir du mauvais matériel, j'ai tout ce qu'il me plait, mais la motivation n'est plus là.

    Maintenant, j'aimerais savoir si certains d'entre vous étaient développeurs (tous langage) et ont aussi fait une reconversion professionnelle ? si oui vers quoi ? quand ? pourquoi ? comment ?

    Ça me taraude de plus en plus.

    git is great because linus did it, mercurial is better because he didn't

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 4.

      M'en parle pas on est en c++ 2003 ici, et je tombe sur du copier/coller ou des macro là où fonction ou template suffirait, je retrouve jusqu'à 6 passage identique dans un même fichier (3*2), trois fois la même chose, dont certains élément à l'intérieur se répètent eux même.

      Il n'est pas rare de retrouver le même bloc de 6 lignes répétées 15 fois… Je ne compte plus les

      if ( mapDeTruc.find(pika) == mapDeTruc.end() ){
         mapDeTruc[pika]=vector<plop>();
      }
      mapDeTruc[pika].push_back(choux);

      ou les find juste avant les insert. Bref même pour des morceaux de langage vieux de 20 ans les gens ne regardent pas la doc. (pour info seule une seule ligne ci-dessus est nécessaire, la dernière;

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Mon avis (professionnel)

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

        Mon préféré (copier/coller que tout le monde fait) dans mon poste actuel c'est le :

        void DoSomething()
        {
            m_mutex.lock();
        
            try {
                DoSomethingElse();
            } catch (...) {
                m_mutex.unlock();
            }
        
            m_mutex.unlock();
        }

        git is great because linus did it, mercurial is better because he didn't

        • [^] # Re: Mon avis (professionnel)

          Posté par  . Évalué à 3.

          mouais c'est pas pour ça qu'on a les scoped_lock ?

          parce que le jour où on rajoute un truc qui pète en dehors du try, on est dans la mouise ;) Surtout que là on a masqué l'exception, ça peut être justifié, ça dépend du contexte ;)

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Mon avis (professionnel)

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

            Effectivement, j'ai oublié qu'ils relancent l'exception après le m_mutex.unlock(). Mais oui les std::lock_guard sont justement là pour éviter ce genre de code scandaleux.

            git is great because linus did it, mercurial is better because he didn't

      • [^] # Re: Mon avis (professionnel)

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

        Ah ben je profite de ton message aussi pour rappeler un détail que j'ai oublié dans ma première réponse. Le syndrome NIH. Dans toutes mes missions en C++, j'ai jamais vu un seul code sans une classe de tableau / chaîne de caractère faite maison. Tous, les ont recodés.

        soupire

        git is great because linus did it, mercurial is better because he didn't

        • [^] # Re: Mon avis (professionnel)

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

          Pour moi, ça prouve surtout que la bibliothèque standard ne satisfait pas les développeurs C++.

          • [^] # Re: Mon avis (professionnel)

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

            Pour moi, ça prouve surtout que la bibliothèque standard ne satisfait pas les développeurs C++

            Ça, c'est un fait. Il y a une tension entre les développeurs qui aimeraient bien qu'il y ait plus de choses dans la bibliothèque standard, parce qu'elles existent dans d'autres bibliothèques standard et que ça simplifierait tout un tas de code, et les éditeurs de la norme (principalement les développeurs de compilateur) qui estiment que ce qui peut être dans une bibliothèque externe n'a rien à faire dans la bibliothèque standard. Dit autrement, ils estiment que si le support du compilateur est nécessaire, alors ça peut rentrer dans la bibliothèque standard mais sinon ouste du balai.

            Par exemple, le fait qu'il n'y ait toujours rien dans la bibliothèque standard pour faire du réseau basique est juste un scandale pour un langage comme C++ (cette fonctionnalité avait été envisagée pour C++20 mais est finalement repoussée pour C++23, au mieux).

            Cependant sur des classes comme std::string ou std::vector, hormis dans certains cas très particuliers qui ne concernent quasiment personne, il n'y a aucun besoin de réimplenter la roue carrée. Parce que les implémentations dans les bibliothèques standard sont éprouvées et optimisées mieux que n'importe quelle autre implémentation.

            • [^] # Re: Mon avis (professionnel)

              Posté par  . Évalué à 3.

              yep j'aime beaucoup celle qui permet de ne même pas avoir d'allocation dynamique sur les petite chaines ;)

              Il ne faut pas décorner les boeufs avant d'avoir semé le vent

            • [^] # Re: Mon avis (professionnel)

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

              N'oubliez pas les utilisateurs qui vont trouver que l'implémentation n'est jamais assez bien, bibliothèque standard ou pas. Un coup il y a trop d'allocations, ou alors les allocateurs par défaut ne conviennent pas. Une autre fois on considère que l'implémentation gère trop de cas et est trop complexe, d'autres fois elle ne gère pas assez bien le cas principal…

              Par exemple j'ai vu des mécontents du fait que la gestion du compteur de std::shared_ptr est thread safe et qu'on paye l'atomic même si le pointeur est restreint à un seul thread. Certains aimeraient aussi avoir la small vector optimization, similaire à small string optimization mais pour std::vector.

              std::function n'est pas assez bien et on vante les mérites de The Fastest Possible C++ Delegates, The Impossibly Fast C++ Delegates ou, encore mieux, The Impossibly Fast C++ Delegates, Fixed ; tout en omettant de noter le manque de souplesse de ces implémentations.

              D'une manière similaire on a pléthore de bibliothèques pour parser du Json, mais laquelle devrait être dans la bibliothèque standard, nlohmann::json avec sa merveilleuse syntaxe et ses performances moyennes ou bien RapidJSON avec sa syntaxe lourde et ses performances impressionnantes ?

              Perso j'ai l'impression que la communauté C++ ne peut pas être satisfaite. Nous voulons des bibliothèques performantes, configurables mais simples à utiliser, avec une syntaxe claire, sans dépendances, génériques mais avec peu de templates et encore moins des macros, mais aussi des temps de compilation courts. Nous voulons un super système de build mais pas CMake parce que sa syntaxe est nulle et pas Meson parce que CMake fait déjà le boulot. Nous voulons aussi un gestionnaire de paquets, mais pas Conan parce que c'est du Python, ni vcpkg parce qu'on ne peut pas spécifier les versions, ni Hunter parce que c'est du CMake. Et au passage on voudrait aussi que les dépendances soient précompilées pour notre compilateur et avec une certaine combinaison de paramètres de compilation.

              Bref, on ne peut pas satisfaire la communauté C++.

              • [^] # Re: Mon avis (professionnel)

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

                Ce que tu décris est la réalité actuelle. Elle vient aussi du fait qu'il n'y a pas vraiment de «chef de projet» (ou de dictateur bénévole) dans C++ et qu'il y a des intérêts fortement contradictoires au sein du comité de normalisation. Et ce n'est pas près de changer.

                On peut pas satisfaire toute la communauté C++ mais on pourrait très bien satisfaire 90% et laisser les 10% restants sur le côté. C'est d'ailleurs ce que fait std::string ou std::vector qui satisfont 90% (voire plus) de la communauté et les autres (notamment dans les jeux vidéos) et bien ils refont leur propre roue et tout le monde est content. Même std::function, ça convient quasiment à tout le monde.

                Mais en ce moment, on n'est plus dans le même schéma. Pour le réseau, plutôt que de standardiser un truc simple (genre ouvrir une socket et envoyer des données dessus), le comité est en train de se prendre la tête sur les exécuteurs. Sur les modules, pareil, je pense qu'ils ont fait de la merde et qu'au final, tous les bénéfices attendues auront disparu tellement le résultat est complexe parce que tout le monde y a mis son grain de sel.

                • [^] # Re: Mon avis (professionnel)

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

                  Qt qui est une grosse lib C++ pourrait tout à fait créer son propre écosystème d'outils purement c++ autour de lui. Et agréger ceux qui veulent suivre.

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

                • [^] # Re: Mon avis (professionnel)

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

                  Sur les modules, pareil, je pense qu'ils ont fait de la merde et qu'au final, tous les bénéfices attendues auront disparu tellement le résultat est complexe parce que tout le monde y a mis son grain de sel.

                  triste pour les modules ;_;

                  Pourrais-tu développer un peu sur ce sujet ? qu'ont-ils fait pour saccager le concept ? C'est vraiment le truc que j'attends le plus, j'en ai marre de parser des headers de plusieurs dizaines de milliers de lignes de code pour chaque fichier source du projet…

                  • [^] # Re: Mon avis (professionnel)

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

                    À la base, les modules étaient censés remplacer les headers et apporter plein d'avantages (dont des temps de compilation plus rapides). Déjà, dès le début, ça s'est mal passé parce qu'il y a eu un consensus pour conserver le préprocesseur (même s'il est isolé au sein d'un module, ça a aboutit à une absurdité, voir plus loin). Ensuite, il y a eu la question des headers déjà existants qu'il fallait gérer. Et puis Google est arrivé avec sa propre solution (dite Atom) concurrente de la solution déjà en place et implémentées par certains compilateurs. Au final, il y a eu des réunions à l'arrache juste avant la deadline pour que tout le monde se mette d'accord sur un truc commun. Ce qui en sort est, de mon point de vue, très bancal. Et surtout, aucune implémentation n'existe, ce qui veut dire qu'on a absolument zéro retour sur une utilisation concrète de cette fonctionnalité fondamentale (alors que généralement, même pour un truc trivial, le comité de normalisation souhaite une implémentation).

                    Les concepteurs d'outils (build, IDE, etc) ont alerté le comité que la proposition finale allait sans doute poser des problèmes. En particulier, quand on fait un import foo, on n'a aucune information sur où pourrait se situer ce module foo. Et il pourrait très bien être n'importe où parce que la norme n'impose aucun schéma de nommage. Et même si on scanne tous les fichiers, il peut être très compliqué de savoir qu'on a trouvé le bon module puisque la directive module peut très bien être le résultat du préprocesseur. Ce qui veut dire que pour détecter de manière sûre l'emplacement d'un module, il faut 1) scanner tous les fichiers, 2) parser les fichiers comme le ferait le préprocesseur. Bref, on nage en plein délire.

                    Les concepteurs d'outils ont aussi alerté sur le fait que la compilation des modules allaient être beaucoup moins parallèle que celle des fichiers actuels. En effet, les modules forment un DAG et il est nécessaire de compiler dans l'ordre topologique, alors qu'avec les fichiers actuels, on peut tout compiler en parallèle et ça passe. Donc, adieu les temps de compilation améliorés. Les concepteurs d'outils ont monté un groupe de travail pour essayer de résoudre tous ces problèmes.

                    Et cerise sur le gâteau, comme la proposition est arrivée très tardivement, la bibliothèque standard n'a pas été modularisée. Donc en C++20, on fera import <vector> à la place de #include <vector>, mais concrètement, ça ne changera rien. De toute façon, pour les templates, il faudra toujours lire la définition quelque part pour l'instancier. Là encore, pour l'instant, il n'y a pas d'amélioration prévue.

                    Pour en savoir plus:

                    Sur ce blog, on trouve aussi une sorte de tuto pour expliquer comment ça va s'utiliser (et ça ne va pas améliorer la réputation de C++ sur sa complexité).

              • [^] # Re: Mon avis (professionnel)

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

                D'une manière similaire on a pléthore de bibliothèques pour parser du Json, mais laquelle devrait être dans la bibliothèque standard, nlohmann::json avec sa merveilleuse syntaxe et ses performances moyennes ou bien RapidJSON avec sa syntaxe lourde et ses performances impressionnantes ?

                Aucune, à mon humble avis la bibliothèque standard n'a aucun intérêt à rajouter une bibliothèque JSON dans le standard. Sinon on va commencer à rajouter tout et n'importe quoi par prétexte que c'est « beaucoup utilisé ».

                git is great because linus did it, mercurial is better because he didn't

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 3.

      Vous avez pas de CI avec une analyse statique de code ? Ni de revue ?

      C'est ce que je reproche à chaque fois au C++, c'est cool d'avoir un C++17 qui est cool, mais on a aucun moyen de garantir qu'on ne continue pas d'utiliser les anciennes méthodes.

    • [^] # Re: Mon avis (professionnel)

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

      Bah, ici, on est bloqué à Visual Studio 2011 en terme de licences. Alors du C++ moderne … je suis pas prêt d'en faire :-).

      Par contre, ils sont un peu plus ouverts sur le Python bien que la version majoritairement déployée soit la version … 3.1 . Oui oui, le truc plus maintenu depuis 2012.

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 10.

      Bonjour,

      Je crois que ce que vous décrivez n'est pas propre au C++, mais plus largement à toute activité nécessitant une forte implication personnelle, une méthodologie et une organisation de travail qui est supérieure à ce que propose et requiert votre situation de travail actuelle.

      En clair, comme pas mal de gens, vous pourriez sombrer dans l'ennui professionnel.
      De plus quand on a passé une grosse journée de boulot à faire des trucs moyens ou inintéressant, il est très difficile de trouver assez d'énergie pour en remettre une louche chez soi.

      Je n'ai pas assez de recul pour être objectif, mais j'ai l'impression que c'est une situation courante, du moins en France. Les métiers à forte technicité ne semblent pas être assez valorisés, peut-être que mon opinion est biaisée mais de ce que je vois on préfère choyer les commerciaux et l'aspect "management" ou financier que ceux qui conçoivent et réalisent le produit.

      C'est une source de frustration et de déconvenue pour le client également. C'est mon ressenti, toutes les boîtes ne sont pas sur le même modèle, il en existe encore fort heureusement qui seraient sans doute ravies de vous compter parmi leur effectif.
      Pour en revenir à C++, c'est presque une lapalissade mais il y a un monde entre le C++ de mes études et les standards actuels, ce qui tend à fractionner la communauté en terme d'usages et "bonnes pratiques". Les concepts innovants collant à l'état de l'art sont parfois ignorés des développeurs vieille école ou des occasionnels non spécialistes. Cas d'école, le "patron" veut un livrable rapidement, les données en entrées sont un gros tas de réels simple précision, il s'en fiche qu'on puisse généraliser le problème, ou même ça lui déplaît car le stagiaire de l'an prochain mettra plus de temps à comprendre le bouzin, et voilà…
      Plutôt qu'une reconversion professionnelle (qui peut aussi avoir son intérêt) tant qu'on a encore la flamme, il est peut-être envisageable de trouver un autre environnement de travail et s'associer à des personnes qui partagent le même point de vue.

      • [^] # Re: Mon avis (professionnel)

        Posté par  . Évalué à 4.

        Tout à fait d'accord avec vous mais j'ai l'impression que le fossé s'agrandit entre développeur passionné et aimant son métier et le modèle de l'entreprise actuel.

        Je commence à être également dans cette même frustration petit à petit. Le pire c'est que dans mon cas, je développe en Python depuis 6 ans ce qui est aussi pas mal recherché pourtant. Mais dans ma région (Alsace - 68) il ne jure que par le PHP, Java, Windev et C#. Alors je peux trouver un poste en Python mais en télétravail, comme c'est le cas actuellement depuis plus d'un an. Le télétravail fait rêver sur le coup mais il a aussi ses limites aussi: moins de contact avec les collègues, sentiment d'isolement, ton lieu de résidence est également ton lieu de travail…

        Après il ne faut pas être trop pessimiste non plus car il existe, bien heureusement, des entreprises où ces développeurs ont un avenir, mais souvent soit:

        • l'entreprise ne recrute plus,
        • il y a trop de monde à vouloir le poste,
        • la localisation ne te le permet pas.

        Donc cela n'est pas si évident de se dire qu'il faut simplement changer d'entreprise. Mais je pense que c'est générationnel et que c'est la période transitoire. Les nouveaux devs ont la vision de la mise à jour constante (je le pense et je l'espère). Fini le "j'ai toujours fait comme ça, ça a toujours fonctionné et c'est pas maintenant que ça va changer". L'informatique ne cesse d'évoluer et cela va devenir une obligation de se mettre à jour. Mais je ne comprends pas pourquoi cela ne se fait pas partout, car c'est tellement intéressant d'apprendre et d'évoluer dans l'informatique.

      • [^] # Re: Mon avis (professionnel)

        Posté par  . Évalué à 2.

        Ayant quitté le monde C++ depuis Mathusalem, je serais intéressé de comprendre ce "monde" qui sépare les différentes moutures du C++.
        Quelques pistes à m'indiquer ?

        • [^] # Re: Mon avis (professionnel)

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

          Pour faire très simple : le C++ a eu plusieurs normes. Quand les développeurs ont commencé à travailler avec le C++ dans les années 2000, on faisait du C++98. C'est la première norme officielle.

          En 2011, la norme C++11 a ajouté une palanquée de nouveautés et nouvelles manière de programmer avec ce langage, tant même que Bjarne Stroustrup a décrit C++ comme un nouveau langage. À part des nouveautés, cela apporte aussi des manières plus sûres de travailler et plus propres. Seulement, le C++11 ainsi que les normes C++14 et C++17 sont imposantes et nécessitent une véritable re-formation personnelles pour appréhender les nouveautés. Et ça, ça demande de l'investissement personnel et un peu de motivation.

          Notez qu'à part le C++, beaucoup de langages évoluent aussi (Java, C#, Rust). Mais il semblerait qu'en C++ la dette technique est souvent plus imposante que dans ces autres langages.

          git is great because linus did it, mercurial is better because he didn't

        • [^] # Re: Mon avis (professionnel)

          Posté par  . Évalué à 2.

          Quelques pistes à m'indiquer ?

          Je vais essayer de faire succin ;)

          • l'intégration de pas mal de fonctionnalité de boost comme les pointeurs intelligents, les regex…
          • les lambda function (permettre la définition d'une fonction lambda, très utile pour tout ce qu'il y a dans std::algorithm
          • le mot clé auto (en gros déduction par le compilateur du type de la variable; très pratique pour les itérateurs :) )
          • variadic template, ou template a nombre variable d'argument (si tu as utilisé le make_shared de boost et regardé sa définition (pré c++ 2011) tu peux comprendre rapidement l'intérêt)
          • la spécialisation partielle de template
          • Plus avancé mais un gros travail sur les rvalue/lvalue, de nouveau type de constructeur (déplacement)
          • de grosses facilité pour l'écriture de template (enable_if<>…)
          • static_assert

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Mon avis (professionnel)

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

        Je suis entièrement d'accord.

        Pour être honnête, lorsque j'ai quitté ma première expérience de trois ans j'ai rejoint une banque via une SSII pour travailler sur les logiciels qui gèrent l'automate (le DAB). C'était absolument parfait, 2 collègues jeunes très orienté nouveautés et expérimentations. Code propre et récent avec bonnes pratiques. En plus, travailler sur des machines rendait le travail moins ennuyant, on passait un peu de temps hors PC. Seul hic, faute de budget la mission s'est arrêté au bout de quatre mois et un collègue et moi y compris avons du quitter cette mission.

        C'est là que tout a commencé, mon manager a décidé de m'envoyer travailler dans une entreprise utilisant encore borland 5 (donc de 1999 !). Ma première véritable depression (avec en plus un facteur agravant dans ma vie personnelle). Les développeurs sont quasiment tous consultants avec un turnover extrême. De ce fait, le code est absolument horrible à maintenir car tout le monde a fait un peu tout et n'importe quoi. Après cette très courte mission, je n'ai pas réussi à trouver un nouvel endroit où je pourrais pleinement profiter du C++ propre. J'ai donc même essayé totalement autre chose en tentant un poste en node.js avec toutes les technologies web récentes. Cette fois ci c'était pas le travail le problème, mais l'immaturité générale des collègues. Depuis je suis dans un poste plutôt convenable à nouveau en C++ avec des collègues en bonne moyenne très intelligents et coopératifs. Dans la majeure partie des cas assez ouvert d'esprit pour apprendre de nouvelles choses.

        Donc à l'heure actuelle mon CV est un peu embrouillé par ce gros passage sombre entre ma première mission et mon poste actuel. D'ailleurs j'ai même été traité de « diva » pendant un entretien d'embauche. C'est aussi pour ça que je me questionne aujourd'hui. Je souhaiterais un peu consolider ma carrière et éventuellement faire une toute nouvelle chose. Car je sais qu'en informatique je serai encore et toujours un éternel insatisfait.

        git is great because linus did it, mercurial is better because he didn't

    • [^] # Re: Mon avis (professionnel)

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

      Pareil pour moi, j'ai fait du C++ pendant quelques années, et puis j'ai fini par être dégoûté par la qualité des bases de code existantes, la complexité du langage, toujours prêt à se retourner contre le développeur. La dernière chose qui a achevé de me détourner du C++, c'est le prix d'un développeur C++ sur le marché qui n'est pas du tout en corrélation avec la difficulté de la techno.

      Du coup, je me suis mis au C# (c'est très facile quand on vient du C++). J'en fait depuis 2/3 ans professionnellement. En parallèle, je me suis mis au Rust. J'ai maintenant un bon niveau, et je suis prêt à partir sur ma première expérience professionnelle dans ce langage (les premiers entretiens se passent bien) :)

      En résumé, tout peut aller très vite : il faut juste se lancer et montrer qu'on en veut et qu'on apprend vite pendant les entretiens.

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 10.

      Je code depuis que j'ai 11-12 ans, et j'en ai 50, et toujours envie de faire ça !
      Mais j'ai une attitude différente vis à vis de la nouveauté. On pourrait même dire que je suis réfractaire au changement !

      Comme toi, j'ai commencé le C++ par moi-même et sur le tas. A la fac, l'orienté objet, c'était soit hyper théorique, soit Smalltalk.
      Quand je code, j'essaye de ne jamais avoir à revenir sur ce que j'ai fait (doux rêve !) et aussi de pondre le code le plus clair possible (c'est pas toujours une réussite, mais on essaye …).

      Du coup, pour le cas particulier des templates, c'est niet pour moi. J'évite les STL, j'en utilise quand je ne peux pas faire autrement (le plus souvent en Qt, avec les QList, QMap, QStringList, etc), et je n'en crée que sous la torture ! Pourquoi ? Parce que la lecture du code en prend un coup je trouve. Et qu'à la moindre connerie, tu te retrouves avec un roman de messages d'erreur qui rivaliserait presque avec une compile COBOL sur l'AS400 de l'IUT il y a 30 ans !
      Et pour le cas général, je n'ai jamais ressenti le besoin de connaître toutes les subtilités de C++11 ou C++14 ou autre. La seule fois où un compilo m'a posé problème, avec un bug avéré, c'était du temps de Visual Studio 6 (il me semble). Je n'ai jamais eu ce genre de problème avec un gcc, quel qu'il soit.

      Dans le domaine auquel je touche le plus souvent, l'embarqué, l'économie de ressource et la performance l'emporte souvent sur la nouveauté. Et puis à mon âge, des buzz-words, j'en ai vu passer un paquet, alors ça fait longtemps que j'ai arrêté de m’exciter ! C'est pas une nouvelle techno qui va révolutionner le schmilblick, à la fin, c'est toujours un processeur qui exécute des instructions bas niveau.

      Et puis, soit disant "techno". Je ne vois pas en quoi le nouveau langage bidule ou la nouvelle API machin révolutionne mon monde. Ah si, ça va ajouter un overhead ici ou là, merci pour les perfs …

      Ajoute à ça le fait qu'actuellement, je suis le seul de mon "espèce" dans la boite (800 personnes, énormément de commerciaux), donc ce que je fais est forcément bien, et j'ai toujours raison !
      Et dans toute ma vie pro, j'ai vu pas mal de monde causer nouvelle techno, et très peu réellement maîtriser. J'ai rencontré un et un seul mec qui savait "faire de l'UML", un et un seul qui connaisse vraiment Java, aucun qui connaisse vraiment tous les tenants et les aboutissants de "la méthode agile". Dans ma boite, plein de gens sont chef de projet, mais personne n'en n'a jamais vu un vrai, ni n'a jamais écrit de spécs ! Et ça répète sans arrêt "on fait" alors qu'on fait faire 99% du temps. A vous dégoutter …

      Après, je veux bien admettre aussi que je suis réfractaire parce que je suis vieux ! Et qu'une réorientation m'a traversé l'esprit aussi. Pas forcément de façon claire et nette. Mais de façon plus vicieuse. Parce que dans ce magnifique pays qui est le notre, il parait de plus en plus difficile de faire les chose. On préfère les faire faire, et être chef, quitte à être incompétent (ou parce qu'on est incompétent …). Comment je fais moi, avec mon métier que j'aime, proche de l'artisanat, avec toujours l'envie de faire, quand on me dit que je coûte trop cher par rapport à un chinois ?

      • [^] # Re: Mon avis (professionnel)

        Posté par  . Évalué à 5.

        Et puis, soit disant "techno". Je ne vois pas en quoi le nouveau langage bidule ou la nouvelle API machin révolutionne mon monde. Ah si, ça va ajouter un overhead ici ou là, merci pour les perfs …

        Je connais 3 contre exemples :

        • go: il semble faire ce que tu recherche, il est simple, vraiment. go ne fais pas de templating ou d'autres choses sophistiquées. Son overhead est vraiment minimal.
        • rust: il me semble que c'est un descendant de C++. Il a des objectifs proches sans l'âge et la dette technique qui va avec.
        • julia: cherche la performance du C avec des choses plus user-friendly que le C++ (moins de piège, une bibliothèque standard plus fournie,…)
      • [^] # Re: Mon avis (professionnel)

        Posté par  . Évalué à 3.

        Et puis, soit disant "techno". Je ne vois pas en quoi le nouveau langage bidule ou la nouvelle API machin révolutionne mon monde. Ah si, ça va ajouter un overhead ici ou là, merci pour les perfs …

        Je ne sais pas si tu l'as fait, mais jette un oeil sur Rust. Pour ma part, sans être dev pro, je me suis intéressé à pas mal de langage. Parmi les langages que j'apprécie particulièrement il y a Ruby, Erlang et Rust que j'ai découvert il y a relativement peu de temps.

        rust devrait te plaire, car l'objectif du langange n'est pas de tester des concepts nouveaux et 'hype', mais plutôt d'utiliser des concepts ayant fait leurs preuves dans un langage reativement moderne.

        L'une des caractéristiques de Rust est de tester plein de choses à la compilation, et de remonter plein de problèmes à ce niveau, un peu comme Ada. Cependant il est beaucoup moins verbeux et prise de tête que ce dernier.

        Personnellement, j'ai mis un peu de temps à m'y mettre mais au final c'est un langage que j'apprécie.

        Certes il est jeune, et certaines choses ne sont pas complètement matures, mais la version 1 est déjà pleinement utilisable. J'espère que ce langage fera ses preuves et sera adopté rapidement.

        • [^] # Re: Mon avis (professionnel)

          Posté par  . Évalué à 2.

          Yep, j'ai lu un truc vite fait sur julia, ça avait l'air sympa.
          Mais encore une fois, le domaine ou le contexte a son mot à dire.
          J'ai lu beaucoup de commentaires qui tournent autour de DB, de Web, etc.
          Mais moi, au moins 80 % du temps, je fais de l'embarqué. Et sorti du C dans le domaine …

          • [^] # Re: Mon avis (professionnel)

            Posté par  . Évalué à 3.

            S'il y a bien un domaine où Rust a ses chances pourtant, c'est bien là.
            Quasi aussi performant que le C/C++, multi-paradigme (le fonctionnel n'est pas juste une Rust-ine), bien plus expressif , toute une batterie de garde-fou contre le bloat code …

            • [^] # Re: Mon avis (professionnel)

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

              Quasi aussi performant que le C/C++, multi-paradigme (le fonctionnel n'est pas juste une Rust-ine), bien plus expressif , toute une batterie de garde-fou contre le bloat code …

              Oui et non.
              Déjà car en embarqué tu as des applications sans OS, donc il te faut forcément une chaîne de compilation qui permette de générer du code valide dans un tel contexte.

              C'est aussi concevoir un OS ou des pilotes ou un logiciel très imbriqué avec le matériel sous-jacent, si Rust est utilisé dans ce contexte (cf Redox), la particularité du domaine impose de contourner les limitations de Rust via l'utilisation des blocs unsafe un peu partout. Du coup, certes tu peux tirer profit des avantages de Rust mais pas autant que pour une application classique où de telles astuces ne sont pas nécessaires.

              L'embarqué c'est aussi le lien entre le binaire et le code qui doit être le plus transparent possible pour faciliter le débogage, avec du C ou du C with class c'est assez transparent. Je n'ai pas pas la sensation qu'avec Rust ce soit aussi transparent et que les outils qui permettent de manipuler ces opérations soit aussi efficaces.

              Sans compter bien entendu que l'embarqué a une grande inertie, sans doute plus grande que le reste de l'industrie, la transition risque d'être très longue.

              Pour moi du coup, l'embarqué sera sans doute le dernier domaine avec la conception d'un OS où le C restera pertinent encore longtemps.

              • [^] # Re: Mon avis (professionnel)

                Posté par  . Évalué à 1.

                Pour moi du coup, l'embarqué sera sans doute le dernier domaine avec la conception d'un OS où le C restera pertinent encore longtemps.

                Pour ma part je pense que parmi tous les langages que j'ai vu, rust est probablement le seul qui pourrait un jour remplacer le C dans l'embarqué. Le langage est encore jeune, mais si ses concepteurs font les bons choix, on pourrait avoir un langage intéressant. Pour moi, et pour ce que j'en vois, le potentiel est là.

              • [^] # Re: Mon avis (professionnel)

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

                Déjà car en embarqué tu as des applications sans OS, donc il te faut forcément une chaîne de compilation qui permette de générer du code valide dans un tel contexte.

                Pas de problème de ce coté là. Il suffit de compiler avec #[no-std]

                impose de contourner les limitations de Rust via l'utilisation des blocs unsafe un peu partout.

                unsafe ne contourne pas les limitation, il utilise un avantage de rust.
                En C, c'est comme si le programme complet était dans un énorme bloc unsafe. Alors que en rust, tu es safe par défaut, mais tu peux dire au compilateur "ici je sais ce que je fait".

                La particularité de rust c'est aussi qu'il permet de faire des abstraction à cout zéro. Donc tu peux abstraire les partie unsafe dans une bibliotheque. Ou utiliser l'une des nombreuse bibliotheque existante pour le support des différent matériel
                https://github.com/rust-embedded/awesome-embedded-rust#peripheral-access-crates
                Ce qui te permet de faire de l'embedded avec peu de unsafe dans ton code.

                En conclusion, rust est un excellent candidat pour faire de l'embedded.
                Il y a pas mal de ressources en ligne: https://docs.rust-embedded.org/

                Il y a toute fois une limitation: rust dépends de LLVM et seule les architectures supportées par LLVM sont supportées par rust. Celà signifie que ça ne fonctionnera pas sur certaine architectures qui nécessite un compilateur proprio par example. Mais bon… il faut éviter ces architectures de toute façon (ça pue c'est pas libre)

                • [^] # Re: Mon avis (professionnel)

                  Posté par  . Évalué à 4. Dernière modification le 04 juin 2019 à 09:21.

                  Il y a toute fois une limitation: rust dépends de LLVM et seule les architectures supportées par LLVM sont supportées par rust. Celà signifie que ça ne fonctionnera pas sur certaine architectures qui nécessite un compilateur proprio par example. Mais bon… il faut éviter ces architectures de toute façon (ça pue c'est pas libre)

                  Oui mais la réalité, c'est que selon les projets, tu vas régulièrement te retrouver avec un processeur comme ci ou comme ca, avec l'outil de build qui v avec.

                  Il faut se rappeler qu'il a fallu la moitié des années 2000 pour que le C soit le développement standard sur ces plateformes alors que les avantages qu'il apporte sont légion.

                  Alors passer a du rust ou je-sais-pas-quel-langage-prometteur pour faire du natif, bof j'ai du mal a y croire.

                  A mon sens, ce qui ce joue aujourd'hui dans l'embarqué c'est plutôt un RTOS relativement standard et qui permettent de facilement coder son projet comme de faire de faire de l'IoT, des upgrade, ce genre de choses. Un truc un peu plus haut niveau que FreeRTOS tel qu'il est aujoud'hui, mais qu'il va peut etre devenir maintenant que c'est piloté par Amazon.

              • [^] # Re: Mon avis (professionnel)

                Posté par  . Évalué à 2.

                Pour moi du coup, l'embarqué sera sans doute le dernier domaine avec la conception d'un OS où le C restera pertinent encore longtemps.

                Il y a quelques temps j'aurais bien dit comme toi, mais je trouve que micropython a vraiment changé la donne.

                Alors certes, ce n'est pas du vrai embarqué de professionnels, mais ça marche super simplement et on trouve de plus en plus de périphériques dont on a les libs, ce qui permet de les tester à une vitesse colossale. Donc, c'est toujours pareil, on pourra toujours faire plus optimisé, utiliser moins de ressources, faire plus de choses à matériel équivalent, mais on parle de carte à 20€ … S'il faut que j'en achète 3 c'est pas bien grave, et en plus comme elles sont connectées en wifi, faire des clients serveurs n'est pas bien difficile !!

                Quand à l'OS e python, sait on jamais, il viendra peut être un jour -->[]

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 7.

      Maintenant, j'aimerais savoir si certains d'entre vous étaient développeurs (tous langage) et ont aussi fait une reconversion professionnelle ? si oui vers quoi ? quand ? pourquoi ? comment ?

      Pour ma part j'ai renoncé dès la fin de mes études (j'ai un maser pro en conception et développement logiciels). J'ai eu plusieurs offres d'embauche (je suppose avoir été détecté comme bon développeur pendant mes études), mais uniquement dans le militaire… je pense que l'argent n'a pas d'odeur, mais je me voyais mal voir aux infos combien de personnes avaient été tuées grâce à ma participation.

      Je suis donc parti à Paris pour acquérir de l'expérience (je visais de devenir architecte logiciel) afin d'avoir plus de possibilités d'embauche lorsque je rentrerai au pays. Cependant je n'avais pas d'argent, j'avais un prêt étudiant à rembourser et un loyer à payer, du coup j'ai signé dans la première SSII qui m'a recruté.

      Par chance, au bout de quelques mois, j'ai été présenté à un client qui avait besoin en urgence d'un expert email expérimenté, et jusque là on ne lui avait proposé que des personnes n'y connaissant rien. J'avais fait une migration de sendmail dans le cadre de mes activités associatives, le client m'a sélectionné dès le premier entretien, presque sans expérience.

      Après 3 ans à travailler dans le mail, j'ai été recruté comme expert GNU/linux chez mon employeur actuel, et là encore je n'avais pas le profil attendu (on cherchait quelqu'un de plus expérimenté ayant en plus des notions de windows, à l'époque je n'y avais jamais touché). Je ne fais presque plus de dev (à part des patchs puisque je suis le seul à savoir écrire et compiler du C, plus quelques scripts pour les clients qui peuvent se les payer, je coûte plus cher qu'un développeur), mais je travaille en prod avec des dizaines de technologies différentes dont je ne maîtrise pas la moitié, et c'est carrément mieux que de faire du dev :

      • j'apprends quelque chose quasiment tous les jours

      • je vois les architectures et les pratiques évoluer

      • lorsque tout est pété et qu'on vient me trouver, je suis considéré comme un héros parce que je sais utiliser strace et le débogueur perl

      • si je rame à trouver la source d'un incident, ça fournit en plus une bonne dose d'adrénaline qui donne aussi de l'intérêt au travail

      • en plus j'ai la chance de pouvoir faire du transfert de connaissances, et je trouve que c'est une autre partie très intéressante de mon travail

      Résultat : je suis depuis 10 ans au même poste, et je n'ai pas prévu de bouger (sauf si j'ai vraiment besoin de beaucoup d'argent rapidement, je pourrais gagner beaucoup plus ailleurs, mais je ne trouverais pas un poste dans lequel je peux être expert dans dans une telle amplitude d'activité).

      Alors lance-toi, monte ton Chaton et publie ton CV, ça recrute !

      https://linuxfr.org/news/demystifier-l-activite-d-hebergeur

      Membre de l'april, et vous ? https://april.org/adherer -- Infini, l'internet libre et non commercial : https://infini.fr

    • [^] # Re: Mon avis (professionnel)

      Posté par  . Évalué à 10.

      Maintenant, j'aimerais savoir si certains d'entre vous étaient développeurs (tous langage) et ont aussi fait une reconversion professionnelle ? si oui vers quoi ? quand ? pourquoi ? comment ?

      Après quelques années à faire du C++ dans une boîte de JV avec des très bon techniciens (bonne connaissance de toutes les fonctionnalités C++), mais de très mauvais concepteurs (syndrome de l'"over design" comme disait un collègue), je suis passé d'abord par du dev d'applicatifs web. Puis, me rendant compte que je ressentais toujours la même chose : plus de goût pour les projets perso, difficulté avec les collègues car trop exigeant (sans doute pas à ton niveau) sur les projets, j'ai décidé de tout plaquer.

      Pendant quelques mois, j'ai suivi une formation d'"Animateur en agroécologie", c'était vraiment génial ! J'ai aussi fait de l'éco construction en chantier participatif, une des plus belle expérience de ma vie.

      De retour à la "réalité" (et oui j'avais besoin de sous), j'ai finalement trouvé un boulot d'accompagnateur pédagogique à Epitech, puis après responsable d'un cursus de dev web pour jeunes décrocheurs scolaires.

      J'ai encore arrêté pour cause de déménagement et enfant, j'ai encore pris du temps pour ma famille et moi-même (c'est vraiment très important je trouve de reprendre le temps de faire autre chose que d'être productif).

      Puis j'ai repris le dev tout en faisant de l'enseignement.

      Aujourd'hui, j'ai trouvé le bon équilibre : je suis dans une CAE (Coopérative d'Activité et d'Emploi) qui me permet d'être indépendant tout en étant salarié de mon activité.

      Je bosse quand je veux/peux et j'ai un salaire que je décide qui tombe tous les mois.

      J'ai fais le choix de peu travailler et d'avoir un petit salaire (proche du SMIC) afin d'avoir du temps pour faire autre chose que du dev pour d'autres personnes.

      Concrètement, je fais du dev quelques mois par an (ça va de 2 à 5 mois) et de la formation initiale et professionnelle de temps en temps. Avec ça, j'ai assez pour vivre toute l'année et le reste du temps je le passe avec mes enfants, à faire des travaux dans la maison (gros gros travaux), du jardinage, etc. Bref, plein de trucs chouettes !!

      Je me sens vraiment moins frustré et quand je dev, je m'éclate vraiment. Je cherche toujours à découvrir une nouvelle techno et y aller bien à fond comme ça c'est super intéressant, je cherche à faire les choses le mieux que je peux (pas toujours évident avec les contraintes de temps) et, comme ça dure pas longtemps, c'est moins frustrant même si dès fois je suis sur des technos totalement à chier.

      Voilà mon petit retour d'expérience, espérons que ça t'inspire :)

      Andréas

    • [^] # Re: Mon avis (professionnel)

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

      Maintenant, j'aimerais savoir si certains d'entre vous étaient développeurs (tous langage) et ont aussi fait une reconversion professionnelle ? si oui vers quoi ? quand ? pourquoi ? comment ?

      Il y a quelques jours, j'étais tombé sur ce portrait : http://anelis.org/portrait-zz-jesse-oscanlan/ le gars s'est reconverti en charpentier.

      • [^] # Re: Mon avis (professionnel)

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

        Jesse, si tu nous lis, à ta santé !

        Et dans la promo précédente, tout en étant un fidèle lecteur de LinuxFr,org, il y a eu aussi un transporteur routier international. Et probablement d'autres profils « atypiques » (y en a un qui voulait faire barman) dont je n'ai pas connaissance (dont un qui a carrément mal tourné pour finir directeur de publication de LinuxFr, entre autres choses).

      • [^] # Re: Mon avis (professionnel)

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

        Passionnant portrait !

        "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

  • # Réunion des développeurs C++ anonymes ;)

    Posté par  . Évalué à 3.

    Très intéressant ce journal et ses commentaires.

    On m'avait dit quand j'étais joueur de jeux vidéos qu'il fallait en général apprendre le C++ pour devenir dév de jeux vidéos. Est-ce que c'est toujours le cas ?

    • [^] # Re: Réunion des développeurs C++ anonymes ;)

      Posté par  . Évalué à 3.

      ça dépend; tu as des VN en python, tu as des casses briques en java (oui oui minecraft rentre dans le domaine casse-briques); tu as un paquet de jeux en html+js (twine assez souvent), tu en a aussi en html5, ou en flash.

      Tu as même pleins de remake des jeux des années 1990 dans le navigateur (lemmings, doom… )

      Par contre la majorité 'gros' jeux (Skyrim, Fallout4…) sont en C++; pour ces deux là tu as un langage de script associé (papyrus) qui permet de d'interfacer les quêtes/sorts/actions et rendent le système plus flexible.

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: Réunion des développeurs C++ anonymes ;)

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

      C'est moins vrai.
      Par exemple, pas mal de jeux utilisent le moteur Unity qui se code en C#.

    • [^] # Re: Réunion des développeurs C++ anonymes ;)

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

      « Dev de jeux vidéos » est un poste très vague aujourd'hui. Aujourd'hui je dirais que si tu veux faire du gameplay ou du dev outils, alors un langage plus moderne comme le C# fera bien l'affaire, voire même directement Unity. Si tu veux faire du code moteur, des algos qui tournent vite, des trucs techniques ou qui utilisent les particularités du matériel, alors apprend le C++.

    • [^] # Re: Réunion des développeurs C++ anonymes ;)

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

      Si tu veux bosser dans les moteurs de jeux AAA, je penses que le C++ est un passage obligé.

  • # Dépêchisable je pense en effet !

    Posté par  (site web personnel, Mastodon) . Évalué à 7. Dernière modification le 03 juin 2019 à 11:39.

    À mon avis, ça vaudrait en effet une dépêche, avec, peut-être, un peu de re-travail, ne serait-ce que pour ceci :

    Il y a plus important que la technologie,
    c’est de se mettre dans la peau du client final
    et de comprendre ses frustrations au quotidien.
    Et on y arrive mieux en intégrant l’utilisateur final
    dans son équipe de développement.

    Je ne sais pas ce qu'en pensent les autres membres de l'équipe de modération.

    « Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.

    • [^] # Re: Dépêchisable je pense en effet !

      Posté par  . Évalué à 0.

      Il y a plus important que la technologie,

      Je suis surpris de lire ça de l'équipe de modération (un représentant du site au fond). La ligne éditoriale a changé ?

      C'est peut-être moi qui me fait des idées, mais j'avais l'impression que la ligne éditoriale principale ici c'était justement les aspects techniques, la technologie quoi. Moi en tout cas c'est pour ça que je viens ici. Parce que ça me passionne et qu'il y a ici beaucoup d'autres passionnés. J'ai d'ailleurs l'impression que sur ce journal il y a 90 % des commentaires qui discutent de points techniques pointus, ce qui est merveilleux.

      Je ne sais pas ce qu'en pensent les autres membres de l'équipe de modération.

      Et les simples membres ? Personnellement je trouve ce journal intéressant, parce que j'y lis un développeur C++ qui semble avoir perdu la flamme (en tout cas c'est mon interprétation). Plus bas dans les commentaires, d'autres sont dans le même cas. Moi-même, après 12 ans de dev pro (et une douzaine de plus en amateur), parfois je les rejoins et suis un peu découragé par les nombreux points qu'ils citent et que je constate aussi. Mais heureusement pour l'instant ça ne dure jamais bien longtemps.

      • [^] # Re: Dépêchisable je pense en effet !

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

        Il y a plus important que la technologie,

        Je suis surpris de lire ça de l'équipe de modération (un représentant du site au fond). La ligne éditoriale a changé ?

        Ce n'est pas parce que des gens aiment un sujet x et passent du temps dessus que ce sujet x est le plus important, petit soucis de logique dans la réflexion ici.
        Et sérieux, si la technologie est le plus important pour toi, faudrait penser à sortir de chez toi.

        J'ai d'ailleurs l'impression que sur ce journal il y a 90 % des commentaires qui discutent de points techniques pointus, ce qui est merveilleux.

        Ca n'enlève pas les 10 autre %, heureusement.

        j'avais l'impression que la ligne éditoriale principale ici c'était […]

        LinuxFr a toujours été un lieu de débat philosophique, de discussion sur les licences et autres sujets liés (DRM…), de moto, de bronsonisation… en plus de la dernière version de Fedora avec une liste de numéros de version des logiciels.

        • [^] # Re: Dépêchisable je pense en effet !

          Posté par  . Évalué à 3. Dernière modification le 05 juin 2019 à 10:15.

          LinuxFr a toujours été un lieu de débat philosophique, de discussion sur les licences et autres sujets liés (DRM…), de moto, de bronsonisation… en plus de la dernière version de Fedora avec une liste de numéros de version des logiciels.

          Tu oublie cinéma (https://linuxfr.org/tags/cinema/public) et la cuisine cuisine (https://linuxfr.org/tags/recette/public)

          Traitre !!!

          Et puis on parle aussi de boulangère et parfois - hem - politique  ;)

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Dépêchisable je pense en effet !

            Posté par  . Évalué à 5.

            la cuisine cuisine

            La cuisine est une pratique récursive qui s'appelle elle-même ? Elle termine ? Est-on garanti d'avoir de quoi manger à l'arrivée ? :-P

            Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

        • [^] # Re: Dépêchisable je pense en effet !

          Posté par  . Évalué à 3.

          Ce n'est pas parce que des gens aiment un sujet x et passent du temps dessus que ce sujet x est le plus important, petit soucis de logique dans la réflexion ici.

          Y a une histoire de contexte. Sur linuxfr, oui je pense que les sujets technologiques sont les plus importants. Mais c'est que mon opinion et les autres membres peuvent ne pas être d'accord (lapalissade).

          Et sérieux, si la technologie est le plus important pour toi, faudrait penser à sortir de chez toi.

          Je n'ai pas dit ça. Et même si je l'avais dit, je n'aime pas beaucoup ce genre de remarque. Il n'existe qu'une seule "bonne" échelle des valeurs et c'est la tienne ?

          LinuxFr a toujours été un lieu de débat philosophique, de discussion sur les licences et autres sujets liés (DRM…), de moto, de bronsonisation… en plus de la dernière version de Fedora avec une liste de numéros de version des logiciels.

          On est d'accord. Mais j'ai pas souvenir d'avoir vu le type de journal que tu cites promu en dépêche. Et ce journal mérite certainement d'être promu, mais je trouve que le point soulevé ("Il y a plus important que la technologie") en est justement la partie la plus discutable sur ce site.

          Mais bref, je ne souhaite pas polémiquer, c'est une perte de temps pour tout le monde. Bonne continuation.

      • [^] # Re: Dépêchisable je pense en effet !

        Posté par  (site web personnel, Mastodon) . Évalué à 4. Dernière modification le 06 juin 2019 à 12:55.

        Je suis surpris de lire ça de l'équipe de modération (un représentant du site au fond). La ligne éditoriale a changé ?

        Non, elle n'a pas changé. Et, oui, il y a plus important que la technologie en soi, c'est le résultat final qui importe avec la prise en compte des utilisatrices et utilisateurs finaux. C'est ce qui permet de faire des produits de bonne qualité et du code qui tient la route. Sinon, cela n'a aucun intérêt. Un logiciel c'est d'abord un outil, pas une fin en soi.

        « Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.

        • [^] # Re: Dépêchisable je pense en effet !

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

          Je suis surpris de lire ça de l'équipe de modération (un représentant du site au fond). La ligne éditoriale a changé ?

          Quelle est la ligne éditoriale ? À ma connaissance il n'y en a pas, pourtant je fréquente le site depuis le début. Les règles de modération indiquent une ligne éditoriale aussi floue que possible : Les thèmes principaux de LinuxFr.org sont Linux et les logiciels libres. D'autres thèmes peuvent être abordés. On essaie d'être d'accord entre modérateurs, c'est tout.

          "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

  • # Livraison facile en Python ??

    Posté par  . Évalué à 5.

    L’intérêt du Python (par rapport au C++) dans ce mode de fonctionnement c’est la livraison :
    on peut se permettre de livrer directement le code source et hop l’utilisateur exécute l’application !

    Alors ceci m'étonne. Je veux arrêter Python pour les difficultés de livraison. On ne peut pas livrer d'exécutables en Python. Peut être que l'utilisateur peut lancer un script facilement, sans besoin de compilation, mais dès qu'il y a besoin de dépendances systèmes (et cela arrive pour des librairies python) ou de plein de librairies python, via pip, c'est une autre paire de manches. Quel confort de livrer un exécutable tout-en-un avec un language compilé !

    • [^] # Re: Livraison facile en Python ??

      Posté par  (site web personnel) . Évalué à 2. Dernière modification le 03 juin 2019 à 12:29.

      Tu as des outils pour packager le tout dans un simple binaire pour Windows ou Mac (pas regardé pour Linux, mais bon c'est déjà plus simple en rajoutant une dépendance au Pytho du repo officiel).
      Mais… Oui, ça revient à faire comme avec C++, en "pire" :-D.

    • [^] # Re: Livraison facile en Python ??

      Posté par  . Évalué à -2.

      Pourquoi ne pas utiliser Docker ?
      Nous avons eu le même problème avec une application Node, cela s'est révélé une très bonne solution.
      Et c'est parfaitement intégrable avec un système de CI/CD (coucou Gitlab :) )

      • [^] # Re: Livraison facile en Python ??

        Posté par  . Évalué à 5.

        parce que tu ne peux pas livrer un exécutable docker à des utilisateurs, parceque je préfèrerais déployer et livrer un exécutable sans une nouvelle couche technologique qui a besoin de temps pour lire la doc, se former, mettre en place la pipeline, mettre à jour l'image docker, pour réparer les bugs pas liés à ton soft, qui a des problèmes de sécurité, etc, etc, etc. Certains languages te construisent un exécutable prêt à l'emploi. Point barre.

        • [^] # Re: Livraison facile en Python ??

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

          Dans un monde où l’empaquetage prends un temps infini avec toutes les variantes OS/CPU/conteneurs, pouvoir générer un exécutable avec toutes ses dépendances statiquement liés, c'est un friture tueuse !

          Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

        • [^] # Re: Livraison facile en Python ??

          Posté par  . Évalué à 4.

          Déjà,
          Vous partez d'axiomes différents.

          Tu veux un exe mais on poses comme préambule qu'in tu veux du python avec des libs implémentées dans un autre langages et donc fortement liées à l'OS

          Je vais pas être désagréable et rappeler comme il est simple d'utiliser toute la batterie des outils C/C++ de cross-compiling pour rire. Je t'invite à lire la liste à la Prévert de l'auteur du journal

          Python est un langage interprété tout comme java a besoin de son runtime.
          Que ça ne te plaise pas, soit!
          Mais si tu fais du pur python c'est pas le bout du monde de faire un pip install (en plus tu peux virtualiser tes envs) ou pondre une exe. Au besoin il est capable de choper des libs natives tout comme un apt-get dis-donc.
          De la part de linuxiens qui ont toujours bavé sur les exe windows et autres .dmg, ça me fait légèrement sourire comme argument.

          C'est sûr avec du Go par exemple, on se retrouve avec 1 binaire. Je sais pas ce qu'il en est de l'édition dynamique, mais ça n'était visiblement pas la priorité il y a quelques temps et pour la portabilité tu repasseras (J'ai qu'à utiliser Docker, c'est ça ?)
          https://medium.com/learning-the-go-programming-language/writing-modular-go-programs-with-plugins-ec46381ee1a9

          C'est peut être pas un hasard que ça ne perce que sur les micro-service du coup.
          Par contre, je le vois pas trop décoller dans tous les domaines où l'expressivité prime bizarrement (les data science par exemple) et coté Devops python est toujours devant on dirait.

          Bref ça correspond pas à ton besoin très bien. En 2019 le dev qui n'a qu'un marteau pour enfoncer des vis ne va pas très loin mais surtout te fatigue pas à "lire des docs". Les autres le font à ta place.

          • [^] # Re: Livraison facile en Python ??

            Posté par  . Évalué à 1.

            Go ne perce pas que sur les micro services.

            Pour le data science, tu as
            https://www.pachyderm.io/
            https://gorgonia.org/
            https://github.com/owulveryck/onnx-go pour charger des modèles onnx depuis Go (et sur certains modèles, il était même plus rapide que tensorflow)

            Et puis c'est sans compter la partie blockchain, la partie wasm, le devops (terraform, vault, ci/cd, …), l'iot, l'embarqué (tinygo), les CLI
            Bref, non, y a pas que les micro services une fois qu'on regarde de plus près. (et moi je développe un jeu vidéo en websocket, web avec frontend généré avec gopherjs puisque y avait pas encore wasm à l'époque)

        • [^] # Re: Livraison facile en Python ??

          Posté par  . Évalué à 1.

          parce que tu ne peux pas livrer un exécutable docker à des utilisateurs

          Non. Mais une image à instancier, disponible sur un registry, régulièrement mise à jour et testée en amont via un système d'intégration continue, si.

          parceque je préfèrerais déployer et livrer un exécutable sans une nouvelle couche technologique qui a besoin de temps pour lire la doc, se former, mettre en place la pipeline, mettre à jour l'image docker, pour réparer les bugs pas liés à ton soft, qui a des problèmes de sécurité, etc, etc, etc

          Cela demande, comme n'importe quelle techno, un investissement en temps. Et ce temps, on ne l'a pas toujours, effectivement. Ceci dit, cela peut également en faire gagner de façon non négligeable une fois le tout en place.
          Pour ce qui est des bugs liés à l'environnement contenu dans l'image, ça nous est arrivé une fois. Je suppose que des outils comme Nix peuvent aider pour avoir des environnements facilement reproductibles, mais je suis loin d'être un spécialiste dans ce domaine.

          Certains languages te construisent un exécutable prêt à l'emploi. Point barre.

          Tout à fait. Je partageais juste un retour d'expérience sur un point : nous ne maîtrisons pas l'environnement dans lequel notre client déploie nos applications. Docker s'est révélé un bon compromis pour avoir un livrable tout en un en faisant abstraction des technologies utilisées, sans aucune autre dépendance que Docker lui-même.

          Après, je conviens volontiers que ce n'est pas adapté à toutes les situations.

    • [^] # Re: Livraison facile en Python ??

      Posté par  . Évalué à 2.

      Déjà il faut voir les usages. Il n'est pas toujours nécessaire d'avoir des dépendances sur du code natif pour bon nombre de projet et le cas échéant ces libs sont plutôt bien empaquetées (par exemple dans le Big Data, PySpark…).

      On ne parle pas forcément de livrer un exe.
      Tu peux vouloir déployer sur un serveur Web, dans un cluster K8S ou simplement un script.

      Ce ne sont pas forcément les même usages.

      Mais ce n'est pas ce que l'auteur voulait exprimer je pense. Il voulait peut-être juste signifier que l'expressivité du langage le rend autrement plus productif et permet donc de livre des incréments plus souvent. Avant la réplique, je n'ai pas dit qu'il était plus performant.

    • [^] # Re: Livraison facile en Python ??

      Posté par  . Évalué à -1.

      Livraison de ton module python et ses dépendances via une image docker :-)

      • [^] # Re: Livraison facile en Python ??

        Posté par  (Mastodon) . Évalué à 3. Dernière modification le 03 juin 2019 à 14:20.

        Livraison de ton module python et ses dépendances via une image docker dockerfile :-)

        Ça n'a pas de sens, tu livres en executant le code sur son infra dédiée, que ce soit sur site ou dans le nuage, sur une simple VM ou dans du kubernetes, openshift, swarm ou une autre solution on s'en branle, c'est ton système d'intégration continue qui va le publier.

        Le client il n'en a rien à faire de ton image, il veut une application qui tourne.

    • [^] # Re: Livraison facile en Python ??

      Posté par  . Évalué à 1.

      Alors je suis tombé sur cette problématique pour mon boulot et c'est effectivement pas simple mais c'est pas infaisable. Par contre il y aura toujours besoin d'avoir des scripts de bootstrap pour avoir exécuter ton environnement.

    • [^] # Re: Livraison facile en Python ??

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

      Je génère systématiquement des exécutables quand je livre des outils écrits en Python. En effet, sinon, la tambouille d'installation est trop rebutante. Py2exe, Py2app et Pyinstaller sont tes amis.

    • [^] # Re: Livraison facile en Python ??

      Posté par  . Évalué à 2.

      On ne peut pas livrer d'exécutables en Python

      Bah si, avec pyinstaller. Ça juste marche !

  • # La technologie est juste un outil

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

    Je suis d'accord avec toi que la technologie reste un simple moyen et non pas un but.

    Concernant le C++, j'en ai fais de nombreuses années et dans un contexte amusant ou il est vraiment justifié : celui du calcul haute performance pour le cinéma d'animation. Sans entrer dans les détails, mais un contrat avec un client peut se perdre si tu es 5% plus lent que la concurrence. Quand le budget alloué aux fermes de rendus pour un film est non négligeable par rapport au budget total du film, on parle de millions d'euros qui se jouent sur 5% de performance.

    Tu parles de reconversion, c'est ce que j'ai fais. Il y tout juste un an, j'ai décidé de quitter ce domaine et de faire autre chose, je voulais changer.

    Depuis, je fais principalement de l'embarqué pour l’aéronautique. Un domaine pour lequel le C++ est sensé être aussi le roi. Sauf qu'en fait non. Dans ce contexte, le C++ est un langage intermédiaire généré par un langage de plus haut niveau (ici Haskell) pour au final avoir un code plus simple (on profite de la souplesse d'Haskell) et plus robuste (On peut prouver de nombreuses choses statiquement pendant la phase de génération du code, choses qu'il nous aurait été impossible de prouver en C++).

    Mes anciennes compétences C++ sont ici utilisées dans l'outil de génération de code C++.

    En ce qui concerne les outils pour le C++, je suis biaisé car je travaille pour une société de consulting qui vend du bazel et du nix, ( https://www.tweag.io/) donc :

    • Bazel, dont tu parles, est un très bon outil pour gérer le build sur une grosse base de code hétérogène. Il saura autant faire cohabiter du C++, que du python, du haskell, du node et que sais-je encore, et ce sur plusieurs architectures. À titre d'exemple, le générateur de code C++ dont je parlais avant est écrit en Haskell, le code C++ est généré sur x86_64 puis compilé en cross compilation pour différentes architectures pour l'embarqué. Tout cela dans bazel.

    • Nix (https://nixos.org/nix/) pour ta gestion de dépendance. En gros, nix va te créer un environnent reproductible contenant les dépendances de ton projet.

    L’expérience windows est correct dans le subsystem for linux. En dehors, j'ai déjà cross compilé des binaires natif windows avec, mais jamais essayé de faire plus. Tout ce qui se lie statiquement facilement doit pouvoir être faisable.

    Le problème de la distribution est réglé avec nix si ta cible peut installer nix. Sinon, tu es dans la même situation que pour tous les autres outils de gestion de dépendance / build et je ne connais qu'une unique solution: faire un binaire statiquement lié qui contient tout. Et nix peut t'aider à faire ça.

  • # Mon avis

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

    Je lis pas mal de message qui concernent l'univers de l'informatique pourrait être appliqués à bien d'autres domaines. Ce que je vois, c'est qu'il y a un fossé en entre ce que l'on aime, et ce qui fait vivre.

    Nous avons l'avantage d'avoir un emploi dans un domaine qui n'a pas de limite en terme de créativité/expression/imagination, et c'est pour ça que des profils atypiques se retrouvent dans l'informatique. Sauf que cette créativité n'est pas ce que l'on souhaite dans l'entreprise (en tout cas pour la plupart), où les besoins premiers sont avant tout d'avoir un code stable, et une "masse de production" prévisible.

    De mon côté, la première chose que j'ai apprise quand j'ai été embauché, et de tester, tester, et encore tester. Aujourd'hui, j'ai encore de la spontanéité dans le code que je peux écrire chez moi, mais qui est avant tout forgée via des années de pratique. Je me rend compte que dans d'autres domaines (travail du bois, calligraphie), je n'arrive plus à improviser comme je pouvais le faire quand je faisais du QuickBasic ; j'ai besoin de préparer ce que je veux faire, faire un premier essai, etc. C'est en changeant d'objet que l'on se rend compte que l'on fini par se reposer sur l'acquis et que l'on perd cette capacité à apprendre par soi-même.

    Cela n'est pas spécifique à l'informatique, je pense que tous les métiers qui ne sont pas aliénants peuvent s'y substituer : un menuisier d'atelier, un cadreur sur un plateau de cinéma, un cuisinier dans restaurant…

    En écrivant le commentaire, je pense à un passage (que je retrouve pas bien sûr), des Sept piliers de la sagesse. En voilà un autre de "Guérilla dans le désert" (de Lawrence, toujours) qui reprend la même idée :

    « Nous n'avions donc pas institué de discipline, au sens où celle-ci contraint, brime l'individu et devient le plus petit commun dénominateur entre les hommes. Dans les armées régulières en temps de paix, cette discipline oblige à ne compter que sur la capacité minimale du plus faible des soldats. On vise, non pas la moyenne, mais au nivellement absolu. Les 99 hommes les plus performants sont astreints à servir au niveau du plus mauvais. » L'industrialisation de l'informatique nous fait prendre ce chemin du nivellement, malheureusement, tous les profils attirés par ce domaine pour son côté technique et créatifs se retrouvent déçu par la direction.

    Entre ces deux extrêmes, il y a encore tout un espace à explorer pour que chacun y trouve son compte.

    • [^] # Re: Mon avis

      Posté par  . Évalué à 2.

      C'est peut-être aussi le moment de rappeler qu'il existe des postes où on a de la liberté pour faire son travail dans de bonnes conditions—toutes les entreprises ne se valent pas, on peut avoir plus ou moins de marge de manœuvre, et il y a des besoins d'informaticiens en dehors du secteur privé (personnellement je suis dans le secteur de la recherche publique, qui embauche des chercheurs mais aussi des ingénieurs, et qui a la valeur du travail bien fait). Ça ne veut pas dire abandonner complètement la recherche de l'efficacité au travail, et il y a aussi souvent des inconvénients à accepter en conséquence (plus difficile d'obtenir un poste stable, salaire plus faible).

      Les personnes qui savent programmer ont la chance d'être dans un domaine où la demande en personnel est très forte. Il est possible d'en profiter pour être un peu difficile sur les offres qu'on accepte, et de ne pas se laisser imposer des environnements de travail qui ne nous conviennent pas.

      • [^] # Re: Mon avis

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

        Honnêtement, pour la recherche publique tu as quand même des contraintes et sources d'embêtements : habiter dans une grande ville (sans quoi rien ou choix très limité), aimer l'avion et les longs déplacements pour juste quelques jours à des conférences (sans quoi moins de publis et donc pas de poste stable), deadlines (plus ou moins contraignant suivant les fois et les collègues avec qui tu publies), accepter de travailler dans un milieu hiérarchisé (grades, échelons, doctorant, post-doc, stagiaires, etc.) et avec inégalités de salaires importantes (comme dans le privé), parfois manque de chance avec certains enseignements (genre se retrouver à donner des TPs dans trois salles différentes à la fois pendant plus d'un mois du fait d'une soi-disant mauvaise évaluation des effectifs; ou encore se retrouver à faire le travail d'un chargé du cours rarement sur le site et qui répond aux mails avec une semaine ou deux de retard quand il répond), de la paperasse (moins qu'ailleurs peut-être, mais une certaine quantité) ; je n'ai fait qu'une thèse, j'ai donc sans doute échappé à pas mal d'autres choses.

        Ceci dit, oui, l'environnement de travail en général et la flexibilité des horaires sont plutôt sympas en recherche. Mais dans d'autres domaines que l'informatique il est peut-être plus facile de se sentir utile avec moins de pression et désagréments aléatoires; je dis peut-être, parce qu'en pratique, quelque soit le domaine, le gagne-pain s'accompagne toujours potentiellement de mauvaises surprises, sauf pour ceux qui ont des économies et peuvent se permettre de partir/se libérer et faire une pause quand ils le veulent.

  • # Confusion et mauvaises solutions

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

    Quand je lis ton poste, j'y vois beaucoup de confusion. Tu pointes de vrai problèmes mais passe à coté de solutions qui existent ou simplement que tu pourrais éviter.

    On réfléchit à une solution de secours, et me voilà chargé de développer une application en Python en intégrant des briques sous licence libre.
    Je travaille alors en étroite collaboration avec les utilisateurs finaux et on sort l’application en quelques mois.

    Et Il y a aucun mal à ça. Un langage de script comme python se prêtera toujours mieux au prototypage. C'est par contre à proscrire pour toute application long terme. Car très vite impossible à maintenir dés que la code base d’élargie.
    Tout dépend de la solution que ton client veut: Un petit tool de dépannage pour une chaine de prod où un service / client qui va être utilisé 10 ans et supporté en prod ?

    En Python, Node.js, Ruby, Go, Rust on a pip, npm, gem, go-get, cargo qui simplifie le téléchargement des dépendances, et l’intégration au projet avec un import xxxx. De plus, certains IDE prennent en charge cette gestion des dépendances.

    Tu confonds trois choses : Configuration, Compilation et Deploiement.

    La configuration se fait avec un buildtool, la compilation se fait avec ton compilateur, le deploiement se fait avec un package manager. La seul différence en node.js, rust ou go est que la communauté te "cache" ses étapes derrière un tool "clé en main" pour le meilleur et pour le pire (il y a des threads entier sur internet sur les horreurs que peuvent faire npm ou pip…). A l'opposé, C++ te donne un contrôle total sur ta chaîne de tooling.

    Si tu veux ta solution "clé en main", je te conseil simplement un combiné Nix + CMake + GCC et tu retrouveras le même modèle que celui que tu connais.

    A mon humble avis, coupler package manager et build tool est une grave erreur. Car elle conduit a des îlots applicatifs isolés impossible à utiliser dans des langages tiers. ( e.g intégrer un tool Go dans un package python ).

    La majorité des problèmes que tu décris dans ton poste: compilation lente, difficulté d'intégrer un composant, trop de build systèmes, mauvaise productivité, vient de ton problème de tooling.

    Autrement dit : Essaie Nix, GUIX ou Spack.

  • # Je hais le C++

    Posté par  . Évalué à 1.

    …mais plutôt qu'un long discours, 2 petits exemples:

    #include <string>
    #include <stdio.h>
    
    int main()
    {
            std::string s("++123");
    
            printf("%s\n", s.substr(2).c_str());
    
            const char *c1 = s.substr(2).c_str();
            printf("%s\n", c1);
    
            std::string s2 = s.substr(2);
            const char *c2 = s2.c_str();
            printf("%s\n", c2);
    }
    #include <iostream>
    
    struct A
    {
        A() { std::cout << "A" << std::endl; }
    };
    
    struct B
    {
        int b;
        B()       : b(0)  { std::cout << "B" << std::endl; }
        B(int _b) : b(_b) { std::cout << "B " <<b << std::endl; }
    };
    
    int b = 1;
    
    int main()
    {
        A();
        B(b);
    }

    Qu'écrivent ces programmes sur la sortie standard ?

    • [^] # Re: Je hais le C++

      Posté par  . Évalué à 1.

      Ça ne compile pas chez moi :

      # g++ calndoa1.cpp
      calndoa1.cpp: In function ‘int main()’:
        si tu relivres du code dont tu ne connais pas
        le résultat et sans commentaire, je t'envoie
        dans une mine de cobol !
      

      Membre de l'april, et vous ? https://april.org/adherer -- Infini, l'internet libre et non commercial : https://infini.fr

      • [^] # Re: Je hais le C++

        Posté par  . Évalué à 6.

        Si je poste ce test, c'est bien que je connais le résultat (après avoir beaucoup galéré) et qu'il n'est pas celui qu'on imagine au premier abord. Si il n'y a pas de commentaire, c'est parce que c'est un test et c'est toi qui doit deviner le problème sans avoir la réponse au milieu de la question…

        Maintenant si tu me dis qu'en C++, il est impossible de comprendre un petit bout de code si il n'y a pas une tera-chiée de commentaires avec, je trouverais ça un peu excessif mais pas loin de la vérité…

    • [^] # Re: Je hais le C++

      Posté par  . Évalué à 4.

      pour le 1, rien de plus que ce qu'on pourrait penser

      123
      123
      123

      le pointeur retourné par c_str() reste valide tant qu'il n'est pas invalidé par une fonction modifiant la string d'origine ;)

      Le deuxième cas est plus compliqué tu as d'ailleurs joué avec une variable globale pour éviter un bon gros warning de compilation (voir une erreur) (pour cet exemple); il t'affiche

      A
      B

      pour ceux qui n'auraient pas compris la blague B(b) est interprété comme B b; une déclaration d'une variable b de type B. Mais bon c'est quoi ton langage préféré ? parce que des blagues de ce genre j'en ai en java, python, C, perl, bash…

      si il avait déclaré une variable locale ou en tant que paramètre

      void fun( int b)
      {
              B(b);
      }

      Il aurait eu une joli erreur de compilation

      plop2.cc:17:5: error: la déclaration de « B b » masque un paramètre

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Je hais le C++

        Posté par  . Évalué à 4. Dernière modification le 04 juin 2019 à 17:33.

        Ben pour le 1, tu as tout faux, même si ton compilateur en a tiré qq chose. Vois le commentaire plus bas pour la réponse.

        Je remarque qu'il y a plusieurs commentaires autour de ce problème que personne n'a pu identifié jusqu'à maintenant, tout en croyant ta réponse. Ça me rassure pas mal sur le fait que le C++ abuse un paquet de monde et que ce bug sur lequel j'ai galéré des heures était bien difficile.

        Pour le 2, effectivement, quand on compile et qu'on cherche à comprendre a posteriori c'est plus facile… je ne comprend pas trop ta remarque sur la variable globale : le but de la totalité du code est précisément de pointer du doigt ce choix débile du C++ d'écrire une instanciation comme un appel de fonction.

        Mon langage de prédilection est le C, si tu as des exemples du même genre je suis preneur, mais je doute que tu arrives au niveau de traîtrise du C++. L'exemple dessous en Python est pas mal, même si je ne m'y connait pas trop.

        Pour le Perl, ahah trop facile, je veux plutôt un exemple opposé (le code fait ce qu'il semble faire), mais tout le monde sait que c'est totalement impossible !

        • [^] # Re: Je hais le C++

          Posté par  . Évalué à 2.

          tu as tout faux, même si ton compilateur en a tiré qq chose

          Je connais le problème des pointeur / référence sur temporaire; il se trouve que dans un environnement simple ton test donnée ne va jamais planter parce que le recouvrement de mémoire n'est pas fait, même valgrind ne râle pas, c'est pour dire! :P

          Le vrai soucis c'est que tu combine du C (stdio.h) avec du C++. normalement, tu ne passe en c_str qu'au dernier moment.

          En C moi j'ai eu ça

          int calculJour(int i )
          {
             static int *tab=NULL;
             [...]
             if ( taille insuffisante)
               tab=realloc(...);
             tab[n]=calculJour(n)
             [...]
             return x;
          }

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 2.

            Rajoute qq caractères à la chaîne, puis compile avec g++-5 et le printf 2 n'écrira rien (en tout cas !chez_moi_ca_marche).

            Il est vrai que forcer du C dans du C++ est critiquable, mais tu n'as parfois pas le choix. Dans mon cas c'était pour des appels GTK.

            • [^] # Re: Je hais le C++

              Posté par  . Évalué à 2. Dernière modification le 05 juin 2019 à 09:34.

              Tu pose une question, je répond, va pas changer l'énoncé ensuite, même valgrind ne bronche pas sur le premier exemple.

              D'un point de vue technique (norme) le pointeur renvoyé c_str() (ou data()) reste valide tant que la chaine initiale n'est pas modifié. La chaine est détruite à la fin de la ligne const char *c1= s.substr(2).c_str(); , et la ligne suivante donne donc théoriquement un comportement indéfini;

              cependant au vu de la taille de la chaine résultante, "123", on est dans le cas de la short string optimisation, ce qui fait que la totalité de la string est stocké sur la pile; non partagé avec qui que ce soit; et donc en absence de nouvelle allocation locale, on y touche pas; donc la mémoire est toujours valide ;) Ce qui fait que ton cas est parfaitement prévisible ;)

              évidemment, si on agrandi la chaine résultante pour ne plus bénéficier de la short string optimisation, on n'alloue plus sur la pile mais le tas, et là tu vas faire broncher valgrind ;)

              Ensuite du C dans du C++, c'est fréquent; par contre je le redis : on ne passe en char* qu'au dernier moment ;)

              Il ne faut pas décorner les boeufs avant d'avoir semé le vent

              • [^] # Re: Je hais le C++

                Posté par  . Évalué à 3. Dernière modification le 05 juin 2019 à 12:36.

                « Ce qui fait que ton cas est parfaitement prévisible »

                Il faudrait peut être arrêter de raconter n'importe quoi pour justifier ton erreur… tu ne réutilises jamais un pointeur sur un objet désalloué, même si c'est sur la stack, même si c'est « y a pas longtemps ». Les optimisations dépendent du compilateur et des options passés, tu peux avoir une interruption qui va modifier la stack entre-temps, tu peux avoir ta bibliothèque qui va effacer la zone mémoire pour des raisons de sécurité, etc…

                • [^] # Re: Je hais le C++

                  Posté par  . Évalué à 2.

                  tu ne réutilises jamais un pointeur sur un objet désalloué

                  On est bien d'accord; mais tu as demandé la sortie de ton morceau de code; je te la donne, et je t'explique pourquoi ton code est prévisible; on est dans un comportement indéfini très bien défini du moment que la sso est présente ; j'y peux rien si tu ressors les exemples d'il y a 20 ans sans te soucier de voir si ils sont d'actualité.

                  tu peux avoir une interruption qui va modifier la stack entre-temps

                  Dans ton programme ? Je demande à voir!

                  tu peux avoir ta bibliothèque qui va effacer la zone mémoire pour des raisons de sécurité

                  Tu continues de changer l'énoncé au fil de l'eau ;) Tu peux aussi avoir une bibliothèque qui ne recouvre pas la mémoire.

                  CC sur Solaris, il y 15 ans t'aurais donné le même résultat; on a même du code critique qui a tournée pendant des années avec des comportements indéfini, et ne c'est pas propre au C++ …

                  {
                    [...]
                    char *b = a
                    // 
                    free (a);
                    return b
                  }

                  On s'est rendu compte de la blague en passant sous linux + gcc, que des chaines vides à la place des résultats ;); le pire c'est que le code de duplication avait été commenté en disant qu'il ne servait à rien…

                  Tu peux aussi redéfinir tes new/delete

                  Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                  • [^] # Re: Je hais le C++

                    Posté par  . Évalué à 0.

                    La uClibc++ n'a pas 20 ans. Mais j'imagine que t'as encore des excuses ridicules en stock pour justifier ta médiocrité en C++ ?

                    • [^] # Re: Je hais le C++

                      Posté par  . Évalué à 2. Dernière modification le 05 juin 2019 à 22:23.

                      La uClibc++ n'a pas 20 ans. Mais j'imagine que t'as encore des excuses ridicules en stock pour justifier ta médiocrité en C++ ?>

                      Prendre comme exemple une lib incomplète ? T'en a d'autre pour justifier ton manque de préparation pour tes tests ? ;)

                      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                      • [^] # Re: Je hais le C++

                        Posté par  . Évalué à 2.

                        Elle est plus que complète pour un programme de type helloworld. Après, interdire d'utilisation toutes les implémentations incomplètes du standard C++… hum oui, tu as raison, ça serait une très bonne idée.

                        • [^] # Re: Je hais le C++

                          Posté par  . Évalué à 2. Dernière modification le 06 juin 2019 à 13:58.

                          Comme je le dis tu continue de changer l'énoncé au fil du fil.

                          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                  • [^] # Re: Je hais le C++

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

                    on est dans un comportement indéfini très bien défini du moment que la sso est présente

                    Tu te trompes. Le programme a un comportement indéfini, et contient donc un bug.
                    Le fait que ça affiche le bon résultat pour toi n'est que par chance. Sso ou pas.

                    • [^] # Re: Je hais le C++

                      Posté par  . Évalué à 2.

                      Le programme a un comportement indéfini, et contient donc un bug.

                      Je ne dis pas le contraire, j'aurais probablement expliquer plus en détail ma première réponse.

                      Le fait que ça affiche le bon résultat pour toi n'est que par chance. Sso ou pas.

                      La chance n'a rien à voir la dedans; c'est la façon dont est implémenté la stl dans g++; clang; si , par exemple te fait une erreur à la compilation. Et je peux relancer le programme 1010 fois, j'aurais toujours le même résultat.

                      C'est typiquement ce genre de bout de code qui peut tourner 20 ans sans broncher, passer les versions de compilos, parce que quelqu'un à voulu faire du printf debugging, et n'a jamais remis le tout sur une ligne, et planter royalement le jour où tu rajoute 3 caractères dans un fichier de conf.

                      Si une version avec une "chaine vraiment trop longue pour rentrer dans la short string optimisation" là donner le 'bon' résultat est du à la chance.

                      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: Je hais le C++

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

      Tu peux trouver le même genre de surprise dans les autres langages:
      ```

      def plop(a=[]):
      … a.append(1)
      … print(a)

      plop()
      [1]
      plop()
      [1, 1]
      ```

      Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

      • [^] # Re: Je hais le C++

        Posté par  . Évalué à 2. Dernière modification le 04 juin 2019 à 15:14.

        l'un de mes préféré en java (valable au moins jusqu'au 8, je ne sais pas pour les suivant)

        Je meuble un peu pour l'indentation :P

        Integer a = new Integer(126);
        Integer b = new Integer(126);
        if ( a==b ) 
          System.out.println("1  : a==b")
        a++;
        b++
        if ( a==b ) 
          System.out.println("2 : a==b")
        a++;
        b++;
        if ( a==b ) 
          System.out.println("3 : a==b")

        Que donne ce petit bout de fonction ?

        et ce qui fait que je hais le java

        class Pika
        {
          void accept(Collection<String>   plop) { [...]}
          void accept(Collection<Integer>  plop) { [...]}
        
        }

        Ne peut pas compiler car il n'existe pas de type Collection<Truc>, en fait on a que des collection d'objet!

        Il ne faut pas décorner les boeufs avant d'avoir semé le vent

        • [^] # Re: Je hais le C++

          Posté par  . Évalué à 7.

          Que donne ce petit bout de fonction ?

          Il crée 2 entiers en outrepassant le cache d'entier donc leur référence n'est pas égale. En incrémentant chacun d'eux on utilise le cache donc leur référence deviennent identiques. En incrémentant une seconde fois, on sort du champ par défaut du cache d'entier donc leur référence est différente.

        • [^] # Re: Je hais le C++

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

          Ça donne : « Corrige ta pull request, ou alors fournis une excellente raison de faire ce que tu fais dans les deux premières lignes ».

          Cela dit, contrairement au C (et peut-être au C++ ?), le comportement est complètement défini et ne dépend pas du compilateur.

          La connaissance libre : https://zestedesavoir.com

      • [^] # Re: Je hais le C++

        Posté par  . Évalué à 5.

        Quelle est ta surprise exactement ?
        Le passage de paramètres par référence ?

        Le fait qu'une liste soit mutable ou c'est parce que t'es nostalgique des pointeurs et des références.

        • [^] # Re: Je hais le C++

          Posté par  . Évalué à 5.

          Moi, ce qui me surprend c’est le fait que le paramètre soit une variable global et pas un paramètre passé par la pile. Et ça, silencieusement.

          En fonction du type du paramètre, l’argument est soit en copie, soit par référence. Ce n’est clairement pas évident pour quelqu’un qui ne maîtrise pas le langage. Note que cette remarque peut-être valable sur d’autre langage, je pense notamment au Java.

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 0.

            Ce n’est clairement pas évident pour quelqu’un qui ne maîtrise pas le langage. Note que cette remarque peut-être valable sur d’autre langage, je pense notamment au Java.

            C'est ça. Moi depuis 15 ans que je ne fais plus de C ou de … Go mais du Python et du Java, ce qui me choque c'est de devoir encore penser à ce que je veux comme type de passage de paramètre et être obligé de faire une gymnastique intellectuelle incessante pour penser à des indirections, voire jouer avec l'arithmétique des pointeurs.

            Allez Dr Sam à la rescousse:
            http://sametmax.com/valeurs-et-references-en-python/

        • [^] # Re: Je hais le C++

          Posté par  . Évalué à 4.

          Toi ça ne te choque pas qu'un paramètre par défaut soit modifié à chaque appel ?

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 1.

            Non puisqu'il est dans la même portée et que le nom "a" est dans le même dictionnaire de variables de la fonction définie, pourquoi ?

            Au contraire, les langages interprétés décuplent le potentiel de méta-programmation et le modèle sur lequel s'appuie python est super simple et bien fichu.

            Pour te dire, je n'avais sincèrement pas pensé que ce point précis était votre questionnement.

            Par contre, j'ai bien noté qui ici fait du python bashing intensif et je crois que je vais nous concocter une petite réponse gratinée à propos de son petit jouet.

            • [^] # Re: Je hais le C++

              Posté par  . Évalué à 3.

              « Non puisqu'il est dans la même portée et que le nom "a" est dans le même dictionnaire de variables de la fonction définie, pourquoi ? »

              Si on refait l'exemple avec un entier, e.g. plop(a=3), on a les même contrainte que tu donnes et pourtant un comportement différent. Donc véritablement tu te fais avoir par ta propre explication.

              Personnellement, oui je trouve ça choquant, mais j'imagine que ce choix a été fait pour optimiser le temps d’exécution.

              • [^] # Re: Je hais le C++

                Posté par  . Évalué à 1.

                Si on refait l'exemple avec un entier, e.g. plop(a=3), on a les même contrainte que tu donnes et pourtant un comportement différent. Donc véritablement tu te fais avoir par ta propre explication.

                a.append(3) ?

                A mon avis, tu chopes simplement une erreur puisqu'un int n'est pas une liste, mais je creuserai à tête reposée quand même pour voir ce qu'il en est. Je ne connais pas non plus le modèle par coeur mais c'est quand même assez simple de l'explorer avec le REPL

                • [^] # Re: Je hais le C++

                  Posté par  . Évalué à 2.

                  >>> plop
                  <function plop at 0x004F6270>
                  
                  >>> dir(plop)
                  ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format
                  __', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '_
                  _module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclassh
                  ook__']
                  
                  >>> plop.__defaults__
                  ([],)
                  

                  Tadaaaa !!!

                  KISS

              • [^] # Re: Je hais le C++

                Posté par  . Évalué à 2.

                J'ai reproduit ton nouveau cas:

                def plop(a=3):
                … a+=1
                … print(a)

                plop()
                4
                plop()
                4

                Effectivement, comme les arguments sont mis sur la pile,
                dans le cas d'un type primitif, on place la valeur mais dans le cas d'un itérable, une référence j'imagine. Ce qui en soit fait sens (une liste de 10000 int sur la pile, ça fait mal)

                Bref, certains langages font le choix de rendre le mode de passage de paramètre (valeur/ref) le plus implicite possible avec parfois des comportements moins prédictibles et d'autres le rendent explicite au prix de la lisibilité et d'une complexité accrue.

                Tiens mois aussi j'ai envie de jouer:

                package main

                import (
                "fmt"
                )

                func main() {
                a := []int{1,2,3}
                slice1 := a[:2]
                slice2 := a[:2]
                slice2 = append(slice2,4) // first append
                slice2[0] = 8 // underlying array still the same, both slice 1 and slice 2 have element 0 == 8
                fmt.Println("slice 1:", slice1) // slice 1: [8 2]
                fmt.Println("slice 2:", slice2) // slice 2: [8 2 4]
                slice2 = append(slice2,4) // array capacity now exceeded, new underlying array created
                slice2[0] = 3 // slice1 still has element 0 == 8, but slice 2 has element 0 == 3
                fmt.Println("slice 1:", slice1) // slice 1: [8 2]
                fmt.Println("slice 2:", slice2) // slice 2: [3 2 4 4]
                }

                • [^] # Re: Je hais le C++

                  Posté par  . Évalué à 1.

                  Et l'explication détaillée de ce cas est dans le lien que j'ai envoyé plus tôt (Valeurs par défaut et référence)

                  Je reprends la recommandation;

                  Bref, évitez les mutables dans les paramètres par défaut à moins de savoir ce que vous faites (cache ou memoization).

            • [^] # Re: Je hais le C++

              Posté par  . Évalué à 3. Dernière modification le 04 juin 2019 à 21:44.

              Au contraire, les langages interprétés décuplent le potentiel de méta-programmation et le modèle sur lequel s'appuie python est super simple et bien fichu.

              Non, il est très limité comparé à Ruby. A chaque fois que j'essaie de jouer avec la méta-programmation en Python, je me trouve a devoir essayer de trouver un moyen de contourner les limites stupides et arbitraires du langage.

              Personnellement je préfère la philosophie de Ruby "qui consiste à aider
              l’utilisateur lorsqu’il a besoin d’assistance et à s’effacer en toute autre circonstance" (Russ Olsen : Les designs patterns en Ruby).

              j'ai bien noté qui ici fait du python bashing intensif

              Pour ma part je me suis abstenu, j'avais pas envie de rentrer dans ce débat mais cette phrase de ta part m'a incité à intervenir.

      • [^] # Re: Je hais le C++

        Posté par  . Évalué à 6.

        En Python, je préfère:

        >>> a=256
        >>> b=256
        >>> a is b
        True
        >>> c=257
        >>> d=257
        >>> c is d
        False

        (marche aussi avec -5 et -6).

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Je hais le C++

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

          J'ai vérifié tellement j'y crois pas :)

          C'est quoi l'explication ?

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 4.

            is != ==

            C’est le même genre de truc que l’exemple en java plus haut, « is » teste l’égalité des références, « == » teste l’égalité des valeurs. Et il y a un cache d’objet pour les petites valeurs de nombres entiers …

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 1.

          • [^] # Re: Je hais le C++

            Posté par  . Évalué à 5.

            is compare les références, pas l'égalité. Et l’interpréteur Python de référence, pour des raisons de performance, cache les objets représentant les entiers de -5 à 256 pour leur donner la même référence (ça fait des économies de mémoire, mais ça donne ce genre de comportement).

            « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

            • [^] # Re: Je hais le C++

              Posté par  . Évalué à -5. Dernière modification le 05 juin 2019 à 00:56.

              C'est quand même affolant d'avoir ce genre de comportement dans un langage de programmation. Mais bon, c'est Pytho, langage incohérent comme pas possible.

              • [^] # Re: Je hais le C++

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

                Bon, on sait que tu n'aimes pas Python, mais quand même… dans quelle logique ferais-tu une comparaison sur les identités d'objets avec des variables qui contiennent des entiers ?

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

              • [^] # Re: Je hais le C++

                Posté par  . Évalué à 6.

                Moi ce qui m’affole c’est des gens qui pensent qu’ils peuvent interchanger l’égalité de références avec l’égalité de valeur et que ça juste marche.

                Je te rassure, Python est en bonne compagnie avec java, Ruby et .net qui font grosso modo la même chose.
                https://en.m.wikipedia.org/wiki/String_interning

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

                • [^] # Re: Je hais le C++

                  Posté par  . Évalué à 1.

                  Le soucis avec ça c'est que parfois tu veux bien une égalité de référence (is, ou == en java), mais que comme le langage décide que certains entiers ou chaines de caractères pointent vers la même…

                  Moi ce qui m'affole, c'est que le comportement change sur des valeurs arbitraire (-6), ajoute à cela que certaines sont immutable, et d'autre mutable, selon les contextes (paramètres par défaut)…

                  Il ne faut pas décorner les boeufs avant d'avoir semé le vent

                  • [^] # Re: Je hais le C++

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

                    Ce qui me choque c'est que l'égalité de référence, qui est un truc à la con utilisée seulement dans des cas particuliers, soit si facile d'accès et ai même son propre mot clé pour.

                    Le plus drôle c'est que cela casse des possibilité d'optimisation intéressantes. Par exemple, la notion de référence, souvent associée au pointeur en mémoire, n'a plus beaucoup de sens quand ton objet n'est pas "en mémoire", si il n'existe que dans un registre par exemple. Ou si ton objet change de place en mémoire dans le cours de sa vie.

            • [^] # Re: Je hais le C++

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

              Merci pour l'explication. J'avais bien compris ce que c'est que is, mais dans cet exemple c'est vrai que le plus curieux est le fait qu'il réponde True.

              En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

              • [^] # Re: Je hais le C++

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

                Si tu relis, pour les entiers de -5 à 256, à chaque fois qu'il tombe sur une de ces valeurs, plutôt que d'aller recréer une valeur (immutable) correspondante en mémoire, il se contente de créer une nouvelle référence sur une valeur existante créée pour cela au démarrage de l'interpréteur.

                De la même façon, les petites chaînes (entre autre tout ce qui est identificateurs dans les modules) sont réutilisées:

                >>> s1 = 'toto'
                >>> s2 = 'toto'
                >>> s1 is s2
                True
                >>> s1="Une très grande chaîne très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande"
                >>> s2="Une très grande chaîne très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande très très grande"
                >>> s2 is s1
                False

                Ça n'a pas d'impact sur la programmation car il n'y a pas de raison d'aller comparer l'identité d'entiers ou de chaînes, et comme ils sont immutables leur valeur est garantie ne pas changer, mais ça améliore l'efficacité au niveau du stockage et des opérations de test d'égalité (en interne, il teste d'abord l'égalité d'identité avant d'avoir à faire une comparaison sur la valeur).

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

                • [^] # Re: Je hais le C++

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

                  oui oui j'ai bien compris :), je remerciais simplement pour l'explication détaillée (et l'explication détaillée c'est bien l'optimisation).

                  En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

    • [^] # Re: Je hais le C++

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

      #include <string>
      #include <stdio.h> // (1)
      
      int main()
      {
              std::string s("++123");
      
              printf("%s\n", s.substr(2).c_str());
      
              const char *c1 = s.substr(2).c_str(); // (2)
              printf("%s\n", c1);
      
              std::string s2 = s.substr(2);
              const char *c2 = s2.c_str();
              printf("%s\n", c2);
      }

      En (1), on ne dit pas stdio.h, mais cstdio.

      En (2), tu joues avec le feu. Tu crées un objet temporaire, tu récupère un pointeur sur les données de cet objet temporaire et après, tu les utilises. C'est une erreur de programmation. KABOOM!

      • [^] # Re: Je hais le C++

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

        En (2), tu joues avec le feu. Tu crées un objet temporaire, tu récupère un pointeur sur les données de cet objet temporaire et après, tu les utilises. C'est une erreur de programmation. KABOOM!

        il n'a pas tort de pointer le problème, le compilo ne bronche pas, même pas un warning, ça fait partie des pièges à la con du C++ avec d'autres pièges à la con, et c'est bien dommage que C++ garde ces pièges.

        • [^] # Re: Je hais le C++

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

          il n'a pas tort de pointer le problème, le compilo ne bronche pas, même pas un warning, ça fait partie des pièges à la con du C++ avec d'autres pièges à la con, et c'est bien dommage que C++ garde ces pièges.

          Ben pourquoi broncherait-il ? La même expression deux lignes plus haut est tout à fait valide (puisque l'objet temporaire disparaît à la fin de l'instruction donc pendant le printf, il est toujours là).

          Ceci dit, il y a des gens qui réfléchissent à améliorer les diagnostics dans ce genre de cas. Vu l'auteur du bouzin, ça devrait arriver dans quelques temps dans tous les compilateurs.

  • # travailler sur l'interface avec le client

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

    se mettre dans la peau du client final et comprendre ses frustrations au quotidien.
    Et on y arrive mieux en intégrant l’utilisateur final dans son équipe de développement.

    C'est ce que j'ai toujours fait pour déveloper des applications de bases de données : en partant toujours de l'interface et en faisant des allers-retours de quelques heures avec le client. Ça va très vite et le client simplifie tout seul ses besoins parce qu'il voit les conséquences sur l'interface.

    "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

  • # Ce que j'aurais tenté

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

    Je trouve surtout que le mainteneur principal a supprimé les fichiers CMakeLists.txt et meson.build en 2017.
    Et celui-ci semble envoyer bouler les contributeurs proposant la compatibilité avec CMake, supprime le titre des Pull Request et on trouve même des commentaires supprimés.

    Crée le meson.build et ajoute le à la wrapDB. Il restera extérieur au projet mais utilisable avec un simple fichier descriptif. Le build system, de même que le packaging, n'a pas besoin de s'intégrer aux forceps dans un logiciel. Le mainteneur définit des outils par défaut, idéalement pas trop nul ni trop inconnus, mais ne peut intégrer tous les systèmes de l'univers. Je comprends donc qu'il refuse des patchs.

    Ensuite ton IDE ne gère pas Meson… Bin je te dirais: pourquoi chercher à gérer un build system avec un IDE qui va essayer de faire des trucs automatiques. Apprends à utiliser Meson et à éditer un meson.build, tu ne devrais pas avoir à choisir ton build system d'après ton IDE, ni choisir ton IDE d'après la compatibilité avec ton build system.

    Pour finir, pour avoir travaillé avec Conan quelques mois, il permet de faire du packaging de manière assez simple, est assez extensible, a une bonne quantité de logiciels déjà prépackagés, gère Meson et CMake… Si tu veux plus de flexibilité que ce que t'offre la wrapdb de Meson, tu peux facilement ajouter ton fichier meson ou cmake pour patcher le paquet avant de le builder.

    Oui c'est plus long que faire un pip install, mais le problème vient du fait que ce n'est pas packagé (ou mal, cf vcpkg), pas du fait que c'est compliqué à installer une fois packagé. Si tu fais le boulot une fois c'est facilement partageable et réutilisable, pour que d'autres n'aient pas à s'arracher les cheveux comme toi. Il suffit de proposer tes modifications upstream à Conan et à la wrapDB de Meson.

  • # Moi, pas du tout expert C++, je ne compte pas abandonner C++

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

    Cela fait plus de vingt ans que je développe, autant professionnellement que pour mes projets personnels, quasi exclusivement en C++. Je n'utilise qu'une partie des possibilités offertes par ce langage, et rares sont les nouveautés que j'adopte. La dernière en date sont les variadic templates, apparus avec C++11. Je ne peux donc prétendre être un expert C++, et ça n'a d'ailleurs jamais été mon ambition.

    Je peux d'autant moins prétendre être un expert C++ que les seules bibliothèques C++ que j'utilise sont… les miennes.

    À mes débuts, il n'y avait pas autant de langages qu'aujourd'hui, et la plupart n'étaient pas très répandus. En outre, comme je connaissais déjà le langage C, c'est tout naturellement que je me suis tourné vers le C++. Ayant, dés le début, fait le choix d'écrire des programmes portables, entre les différences de comportement d'une même bibliothèque d'une plateforme à l'autre, et les bugs de certaines bibliothèques, je me suis retrouvé à écrire mes propres bibliothèques C++, codées en interne en C.

    Cela est grandement facilité par le fait qu'avec C++, j'ai directement accès aux bibliothèques C standards, ainsi que systèmes, voire à l'assembleur. J'utilise donc exactement le même environnement de développement pour, d'une part, développer mes bibliothèques C++ (en C ou en assembleur), et, d'autre part, pour développer les logiciels qui s'appuient sur ces bibliothèques. Avec la plupart des autres langages, pour avoir des performances optimales, j'aurais dû quand même développer les bibliothèques en C ou en C++, et donc avoir deux environnements de développement radicalement différents. Pour le jeune aspirant développeur que j'étais à l'époque, cela aurait été probablement rédhibitoire.

    Rétrospectivement, bien que ce choix ai été dicté par les circonstances, coder dans un langage sans en utiliser les bibliothèques standards paraît tout à fait insensé, encore plus de nos jours. Pourtant, c'est un choix que je ne regrette absolument pas. L'avantage est que j'ai des bibliothèques avec une API sur mesure, vu que je peux la modifier comme bon me semble, et dont les performances ne sont limitées que par les caractéristiques de la machine sur laquelle sont exécutés mes logiciels. L'inconvénient, c'est que, aujourd'hui, je suis le seul à vouloir/pouvoir modifier mes logiciels, essentiellement parce que mes bibliothèques ne sont pas documentées.

    Ces derniers mois, j'ai eu l'occasion de réaliser des développements pour Java, Node.js, PHP, Python, Ruby et je suis actuellement en train d'en réaliser pour Perl. Bien que j'ai trouvé certains de ces langages intéressants par certains aspects, je préfère, et de loin, coder en C++. Mais cela est probablement dû à ma manière inhabituelle de coder en C++, c'est-à-dire en utilisant exclusivement des bibliothèques maisons.

    Cette manière de coder est hautement critiquable et ne saurait être encouragée. N'empêche que c'est la mienne et qu'elle me convient parfaitement. Et il se trouve que C++ est l'un des rares langages (le seul à ma connaissance, avec le C) qui facilite autant cette manière de coder, autant par l'ouverture de son environnement de développement (accès direct au C et à l'assembleur), que par les performances qu'il permet d'obtenir (qui n'ont rien à envier à celles des bibliothèques fournies en standard).

    Voilà donc un autre point de vue d'un développeur C++ ayant eu un début de parcours fort similaire au tien.

    Concernant certains des points évoqués dans ton journal.

    Je ne trouve pas que développer en C++ est lent, mais c'est probablement parce que j'ai une flopée de bibliothèques pour mettre facilement et rapidement en œuvre toutes les fonctionnalités dont j'ai pu avoir besoin au cours de mes différents développements. Certes, développer ces bibliothèques m'a pris du temps, mais cela s'est fait au fil de l'eau, en généralisant au maximum et en déportant chaque nouvelle fonctionnalité dans une bibliothèque dés que j'ai eu besoin de cette fonctionnalité pour un logiciel.

    Pour ce qui est de la compilation, vu que je n'ai jamais de dépendances du fait que je n'utilise pas de bibliothèques tiers, je n'ai besoin que d'un Makefile pour la compilation. Ce Makefile est généré à partir d'un fichier projet avec un format maison qui se contente, en gros, d'indiquer la nature du projet (exécutable, bibliothèque dynamique…), et de lister les bibliothèques utilisées. Ce fichier projet sert d'ailleurs aussi au paquetage automatique des sources de l'application dans le but de la distribuer.

    Le seul gros manque, c'est une méthode standard de paquetage, ainsi qu'éventuellement un dépôt officiel. Ce n'est pas tellement gênant pour des développement à façon, car je fournis au client généralement un .zip avec les binaires. Mais pour tout mes développements open source, à part pour Windows, je ne sais pas comment faire pour mettre à disposition mes logiciels sans les faire compiler par l'utilisateur, ce qui implique qu'il ai un compilateur C++, en plus de make.

    Cyberdépendance, cyberharcèlement, pédocriminalité… : Zelbinium, pour que les smartphones soient la solution, pas le problème !

Suivre le flux des commentaires

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