Sommaire
-
- Étape 1 : Vous croyez que vous pouvez faire en sorte que Go se comporte comme un langage orienté objet
- Etape 2 : Vous pensez que les goroutines vont résoudre tous vos problèmes
- Étape 3 : Vous pensez qu'au lieu d'une programmation orientée objet, les interfaces vont résoudre tous vos problèmes.
- Étape 4 : Vous croyez que les channels résoudront tous vos problèmes
- Étape 5 : Vous pensez maintenant que Go n'est pas aussi puissant que ce que les gens prétendent.
- Étape 6 : Vous réalisez que les étapes 1 à 5 n'étaient que votre imagination.
- Étape 7 : Vous êtes maintenant en paix
Je vous propose ici une traduction sans prétention d'un article de Daisuke Maki publié sur www.opensource.com concernant les différentes étapes à traverser pour devenir un vrai programmeur en Go sur base de son expérience. Si vous maîtrisez l'anglais, la lecture de l'original sera sans doute plus agréable.
Que vous soyez nouveau à Go ou que vous soyez un utilisateur chevronné, vous reconnaîtrez peut-être ces étapes sur le chemin de l’illumination.
Un jour, au travail, nous discutions du langage de programmation Go. À un moment donné, j'ai commenté une diapositive d'un collègue (co-worker) en disant quelque chose du genre :
"Je pense que c'est similaire à la troisième étape des sept étapes pour devenir un programmeur Go."
Naturellement, mes collègues (co-workers) voulaient connaître le reste des étapes, alors je les ai brièvement décrites. Voici, développées avec plus de contexte, les sept étapes pour devenir un programmeur Go. Peut-être pourrez vous vous voir sur ce cheminement.
Étape 1 : Vous croyez que vous pouvez faire en sorte que Go se comporte comme un langage orienté objet
Après votre premier passage sur Un tour de Go, vous commencez à vous dire : « Maintenant, comment puis-je faire en sorte que ce langage se comporte davantage comme un langage orienté objet… ? » Après tout, vous êtes habitué à ce genre de choses. Vous voulez faire du code robuste. Vous voulez du polymorphisme.
Vous vous dites : "Il doit y avoir un moyen !". Et vous trouvez l'incrustation des strutures (struct embedding). Cela vous permet de déléguer intelligemment les méthodes de l'objet inclus à l'objet incorporé sans avoir à dupliquer le code. Super !
Bien sûr, ce n'est pas vrai. L’incrustation vous permet seulement de déléguer des appels de méthode. Même s'il semble que vous effectuez une répartition de méthode polymorphe, cela n’est pas le cas. En effet, le récepteur de l'appel de méthode n'est pas l'objet enfermant : le récepteur est toujours l'objet incorporé auquel l'appel de méthode a été délégué.
Vous NE FAITES PAS de programmation orientée objet dans Go. Point final.
Etape 2 : Vous pensez que les goroutines vont résoudre tous vos problèmes
Vous avez été attiré à Go par la promesse qu'il vous permettra d'exécuter facilement du code concurrent, ce qu’il fait via les goroutines ! Tout ce que vous avez à faire est d’utiliser le mot-clé go, et vous pouvez exécuter à peu près n’importe quelle fonction ou appel de méthode simultanément. Il est donc naturel que vous souhaitiez maximiser l'efficacité de votre code en créant autant de code à exécuter en parallèle. Et parce que vous masquez ce fait en faisant vos appels de fonction pour créer automatiquement des goroutines, l'appelant n'a même pas besoin d'en être conscient.
Bon, ça pourrait rendre votre code un peu plus compliqué mais maintenant tout fonctionne en même temps !
Go vous permet de créer des millions de goroutines sans sacrifier beaucoup d’efficacité, mais vous ne devriez pas vraiment utiliser les goroutines juste parce que vous le pouvez. Un code simultané est plus difficile à maintenir et à déboguer que le code qui ne circule que dans un seul thread. Autrement dit, avez-vous sérieusement réfléchi à la question de savoir si vos objets partagés sont vraiment synchronisés correctement lorsqu’ils sont accessibles depuis plusieurs goroutines à la fois ? Êtes-vous sûr que l’ordre d’exécution est absolument correct ? Avez-vous vraiment vérifié si ces goroutines disparaissent vraiment quand on n’en a plus besoin ?
Les goroutines sont utilisées au mieux lorsqu’elles sont réellement nécessaires, et à moins que vos exigences ne vous obligent à tout faire en mémoire ou autre, vous ne devriez jamais abandonner l’utilisation des bons vieux modèles multi-processus.
Enfin, N'ESSAYEZ PAS de créer des goroutines dans le dos de vos utilisateurs, surtout si vous écrivez une bibliothèque. Les appels explicites à l'utilisation des appels de go donnent généralement à l'utilisateur plus de flexibilité et de puissance.
Les goroutines ne font pas plus que ce qu’elles font. Utilisez-les seulement lorsque cela a vraiment du sens.
Étape 3 : Vous pensez qu'au lieu d'une programmation orientée objet, les interfaces vont résoudre tous vos problèmes.
Après avoir perdu vos illusions de pouvoir faire en sorte que vos objets se comportent de manière polymorphe, vous réalisez soudain les capacités offertes par les interfaces. Les interfaces vous permettent de décrire les APIs ; il doit y avoir un moyen de les utiliser pour écrire du code plus robuste.
Donc maintenant, quand vous écrivez des bibliothèques, vous définissez des interfaces pour tout. Vous exportez seulement les interfaces et avez des structures privées pour que l’encapsulation soit parfaite. Cela devrait également vous donner plus de flexibilité lors de modifications de l'implémentation sous-jacente, car vous avez maintenant réussi à découpler l'API de son implémentation.
Les interfaces vous donnent beaucoup de puissance, mais ce n’est pas une solution toute faite. Cela ne fournit toujours pas de véritable polymorphisme au sens de la programmation orientée objet. Vous êtes également limité par le fait que les interfaces ne peuvent définir que l'API et que vous ne pouvez y associer aucune donnée.
De plus, bien qu’il y ait des cas légitimes où exporter uniquement des interfaces au lieu de structures en béton soit logique, cela ne devrait vraiment pas être votre mode de fonctionnement par défaut. Les interfaces sont meilleures lorsqu’elles sont petites (par opposition à la description d’une liste complète de méthodes définies pour un objet). De plus, si vous n’êtes pas prudent, vous devrez soit écrire beaucoup d’options pour remplir l’interface, soit écrire du code qui nécessite beaucoup de vérifications de type.
Pour tirer le meilleur parti des interfaces, vous ne devez les utiliser que lorsque vous voulez rendre certains types interchangeables.
Étape 4 : Vous croyez que les channels résoudront tous vos problèmes
Après avoir passé beaucoup de temps à réfléchir sur la façon de forcer Go à travailler de votre façon, vous êtes maintenant à la recherche de cette pièce manquante qui va tout faire fonctionner à votre façon. "Attendez, il y a encore des channels !"
Les channels gèrent correctement implicitement les accès simultanés. Vous pensez qu’il devrait être possible de contourner plusieurs des obstacles rencontrés jusqu’à présent en utilisant intelligemment les channels pour gérer la synchronisation, retourner les valeurs, et le contrôle de flux avec des instructions sélectionnées avec différents channels.
Encore une fois, les canaux sont extrêmement utiles, mais ils sont seulement aussi utiles que leur but initial, qui est de fournir une primitive pour passer des valeurs entre goroutines.
Je suis sûr que vous trouverez beaucoup d’idiomes Go utilisant des canaux : pour les timeouts, le blocage des Entrés/Sorties, les astuces de synchronisation, etc. Mais encore une fois, parce que les channels sont des constructions de concurrence (concurency constructs), en abuser conduira à un code plus compliqué, difficile à déboguer.
Étape 5 : Vous pensez maintenant que Go n'est pas aussi puissant que ce que les gens prétendent.
"Pourquoi ?! Pourquoi est-ce si douloureux d'écrire du code en Go ? Ça ne me permet pas d'écrire du code comme je l’ai toujours fait."
Vous êtes frustré. Pas de polymorphisme. La concomitance est difficile. Les chaînes ne résolvent pas vos problèmes. Vous ne comprenez même pas pourquoi Go existe. Vous avez l’impression d’avoir été dépouillé de tous les beaux outils et de toutes les belles constructions que d’autres langages vous offrent.
Vous croyez que des outils plus puissants pour exprimer des idées abstraites sont absolument nécessaires. Go ne suffit pas.
Go est résolument tourné vers l’avenir. Je viens d’une famille Perl, et pendant un moment je n’arrivais pas à croire à quel point le Go était limitatif. Donc oui, je comprends que vous soyez frustré.
Mais est-ce parce que le langage est vraiment contraignant, ou est-ce parce que vous essayez de le faire fonctionner comme vous le voulez, sans tenir compte de ce que les auteurs du langage avaient l’intention de faire ?
Étape 6 : Vous réalisez que les étapes 1 à 5 n'étaient que votre imagination.
À un moment donné, vous décidez à contrecœur d’écrire du code Go en fonction de la façon dont la plupart des bibliothèques standard sont écrites. Vous renoncez également d’essayer d’être intelligent, et vous commencez à écrire du code simple.
Alors, une voix intérieure déclare : Tu ne voulais pas accepter la voie du Go.
Tout commence à avoir un sens.
Sérieusement, l’apprentissage du Go nécessite un peu de désapprentissage. J’ai dû désapprendre un peu la programmation orientée objet, en plus d’accepter le fait que peu importe le nombre d’outils utiles que le langage peut vous donner, écrire du code concurrent est tout simplement trop difficile pour de simples mortels. J’ai aussi dû désapprendre à utiliser des exceptions.
Je n’ai pas vérifié avec les auteurs de Go, donc c’est juste mon opinion, mais je crois que l’objectif du langage est de rendre plus difficile pour les développeurs d’écrire du code complexe. Il vous donne assez de code pour écrire du code qui exécute des tâches complexes, mais en supprimant certains outils clés, le code que vous finissez par écrire est plus simple et plus difficile à gâcher.
Une fois que j’ai décidé d’accepter les fonctionnalités et les structures telles qu’elles sont, écrire du code Go est devenu beaucoup plus facile, et certainement beaucoup plus amusant.
Étape 7 : Vous êtes maintenant en paix
Vous avez accepté la voie du Go. Vous écrivez maintenant tout, y compris ce pour quoi vous auriez normalement utilisé Perl/Ruby/Python, dans Go. Vous réalisez que if err != nil ne vous dérange plus. Vous n’utilisez les goroutines et les canaux que lorsque cela est nécessaire.
Vous ne faites qu’un avec le Gopher (aucune idée comment traduire ce mot). Vous sentez son chi glorieux, et pleurez quand vous vous rendez compte de sa miséricorde pour vous permettre d’écrire du code dans un langage aussi majestueux.
Félicitations. Félicitations. Maintenant vous êtes un programmeur Go.
Même si cela peut sembler un peu ironique, ce sont des problèmes réels que j’ai ressentis ou vécus lorsque je m’habituais à Go. Peut-être que vous êtes d’accord, peut-être que non, mais l’étape 6 s’est vraiment déroulé comme ça pour moi. J’ai finalement renoncé à essayer de faire fonctionner Go comme je le voulais et j’ai décidé d’écrire ce que Go me disait de faire. Ça a l’air idiot, mais après ça, les choses ont vraiment commencé à avoir un sens.
# Bof
Posté par barmic . Évalué à 8.
Beaucoup de mot pour dire qu'il faut utiliser les choses à vin escient. Ça marche pour tous les langages, toutes les techno et un peu tout dans la vie.
Il y avait une blague là dessus dans le temps avec une suite de phrases :
"j'avais un problème, j'ai décidé d'utiliser x, j'ai eu…". Par exemple "j'avais un problème, j'ai utilisé java, j'ai eu une AbstractFactory de problèmes".
[^] # Re: Bof
Posté par devnewton 🍺 (site web personnel) . Évalué à 5.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
# Expressivité
Posté par barmic . Évalué à 6.
C'est une éloge à l'inéxpréssivité. C'est loin d'être le seul langage qui suit cette voie Pascal et Python sont dans ce train là. Ça permet de n'avoir que du code trivial, sans particularité. N'importe qui peut prendre n'importe quel code sans encombre. Mais ça produit un max de boiler plate et le manque de concision peut poser des problèmes de lisibilité.
D'autres langages cherchent au contraire l'expréssivité maximale comme scala, c++ ou ocaml. Leur idée c'est qu'il faut que le programme reflète la vision du programmeur pour qu'il donne un maximum d'informations au compilateur qui saura en tirer partie. Mais c'est des langages plus complexe à apprendre au final.
Les 2 approches ont du sens, il faut juste savoir embrasser la philosophie de la techno que tu utilise encore une fois ça n'a pas de rapport avec go
[^] # Re: Expressivité
Posté par arnaudus . Évalué à 6.
Et tu mets donc C++ dans la catégorie des langages "concis"? Je ne suis pas sûr de comprendre là où tu veux en venir.
[^] # Re: Expressivité
Posté par barmic . Évalué à 4.
Je met le C++ dans la catégorie des langages qui ont une haute expressivité. Ces langages sont généralement plus concis que leur homologues plus simples.
Et oui le C++ est plutôt concis amha et il le devient de plus en plus. Je ne connais pas d'autres langages qui puisse exprimer la même chose, certains s'en approchent avec beaucoup plus de boilerplate. La métaprogrammation aide beaucoup à être concis (même si dans bien des cas c'est au détriment de la lisibilité). LA possibilité de redéfinir les opérateurs peut aussi rendre un code plus concis.
La notion de lisibilité elle-même est assez complexe. Est-il plus lisible d'écrire des pages de phrases de 3 mots (sujet + verbe + complément et juste quelques verbes différents) ou un paragraphe de phrases plus complexe ? Probablement quelque chose entre les 2. Chaque langage fais un choix entre expressivité et simplicité. Le boulot du développeur c'est de comprendre la logique de son outil pour tomber ni dans l'over engineering ni dans la primitive obsession.
[^] # Re: Expressivité
Posté par arnaudus . Évalué à 2.
Désolé, cette corrélation me semble assez douteuse. Les langages dits de «haut niveau» (typiquement les langages interprétés) sont souvent très concis, au contraire. Tu prends perl ou python, tu peux souvent écrire des scripts de quelques lignes qui enchaînent des séries d'opérations complexes, en faisant souvent appel à une grosse bibliothèque de base.
Au contraire, un langage comme C++ est extrêmement verbeux. La preuve, c'est qu'une partie substantielle de ses évolutions ont consisté à diminuer sa verbosité, ou plus exactement à la masquer (l'inférence de type, par exemple). C'est sûr que grâce à des tétrachiées de .h qui listent des typedefs, on peut gagner des octets, mais ça revient à jouer sur les mots. C++ est un langage extrêmement verbeux ; on peut se retrouver à écrire des pages de code complètement trivial pour implémenter les méthodes d'une classe, ou une série de constructeurs de copie et d'opérateurs d'affectation.
[^] # Re: Expressivité
Posté par barmic . Évalué à 2. Dernière modification le 25 mars 2019 à 14:43.
Ce n'est pas une question de haut ou bas niveau. AMHA Perl et ruby sont bien plus expressif que python qui lui établi une bonne façon de faire et cherche la simplicité du code.
La métaprogrammation a toujours était une base du C++ est c'est un outil de génération de code. Il n'y a rien de neuf là dedans.
Ces constructions ont presque toutes une forme condensée qui me semble plutôt légère. Là où la tentative d'être explicite en python en plus de la volonté de garder une syntaxe triviale empêche d'avoir de nouvelles constructions légères.
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 5.
J'ai du mal à voir C++ et expressivité dans la même phrase, et Python dans la catégorie "inexpressivité". Pour le reste du commentaire, je suis plutôt d'accord.
J'exprime mon désaccord sur les deux points:
Python est au contraire un langage très expressif, le programmeur peut manifester son intention en très peu de lignes de code. Le boiler-plate code en Python est quasiment inexistant.
A l'opposé, à chaque fois que j'utilise la STL en C++, mes yeux pleurent, je me dis que 120 colonnes pour une ligne, c'est bien peu quand tu veux manipuler une structure un tant soit peu élaborée.
Allez, au hasard, parcourons une map/un dict de string vers des paires de string en Python et en C++ et inversons les paires:
En Python:
En C++:
En terme d'expressivité et lisibilité, je trouve que la version Python s'en sort beaucoup beaucoup mieux.
Et encore, il aurait été de bon ton d'expliciter l'instanciation de make_pair<> .
Alors, certes, en C++11, on peut faire plus compact en utilisant des auto et surement avec d'autres trucs (lambda ? foreach ?). Mais tout le monde ne les connait pas.
On peut aussi faire bien plus compact en Python mais on tombe sur le même problème: la syntaxe des Python compréhensions est peu connue (par exemple, aucun de mes collègues de travail ne connait):
d = { k:(v[1],v[0]) for k,v in d.items()}
[^] # Re: Expressivité
Posté par Clément V . Évalué à 5.
Tu fais une recherche dans la map à chaque itération. C'est inutilement complexe. Tu devrais utiliser l'itérateur directement.
En C++ moderne, c'est :
[^] # Re: Expressivité
Posté par Clément V . Évalué à 4.
En fait, ça doit être mieux comme ça :
Et en python, on ne peut pas modifier directement la paire ?
[^] # Re: Expressivité
Posté par Jean Gabes (site web personnel) . Évalué à 2.
Non, la paire ici est un tuple, que tu ne peux pas modifier. Tu dois en recréer un et le réassigner dans le dict.
[^] # Re: Expressivité
Posté par Gof (site web personnel) . Évalué à 1. Dernière modification le 26 mars 2019 à 16:54.
Message supprimé
[^] # Re: Expressivité
Posté par David Marec . Évalué à 2. Dernière modification le 25 mars 2019 à 13:05.
Il faudrait expliquer en quoi
v
représente une paire en python.A vue de nez, c'est un tableau à au moins deux éléments.
Si le dictionnaire contient des paires, non.
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 3.
Il est courant en Python de ne pas s'embêter avec un gros formalisme quand ce n'est pas nécessaire.
La façon la plus simple de représenter une paire est d'utiliser un tuple de deux éléments. C'est une structure non-modifiable, donc ça correspond bien à la définition d'une paire.
Si on se retrouvait avec un programme manipulant des paires ayant des significations variées, on serait amené à utiliser une structure de plus haut niveau, genre un NamedTuple ou une DataClass qui permettrait d'accéder aux deux éléments de la paire avec un nom qui les représente, genre x/y ou first/second, ou encore firstName/lastName.
Genre :
Dans le cas où on manipulerait des coordonnées et qu'on veuille faire une transposition.d[k] = Point(x=v.y, y=v.x)
Mais bon, souvent, les structure de Python sont suffisamment élaborées pour pouvoir les utiliser longtemps en l'état.
[^] # Re: Expressivité
Posté par barmic . Évalué à 2.
C'est assez subjectif et je peux tout à fait me tromper :)
Hum… Certaines choses comme l'une des règles du Zen of python : « There should be one-- and preferably only one --obvious way to do it ». Ne vont pas vraiment dans ce sens. J'ai tendance à toujours le comparer à perl qui a la règle parfaitement inverse, le TMTOWTDI.
Hum… Je n'ai pas trop cette sensation (encore une fois je peux me planter). Quand je vois les exemples de serge_sans_paille je ne vois pas de boiller plate justement.
Et depuis il y a le C++ 14 et 17, les fonctionnalités de C++20 sont aussi déjà établies. Mais ça c'est la complexité du langage. Scala est très complexe, mais très expressif.
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 2.
Tu pourrais être plus explicite ? Je ne vois pas en quoi le fait de favoriser "une façon évidente et si possible unique" de faire une tâche nuit à l'expressivité du langage. Au contraire, si il y une façon évidente et unique de faire une tâche, tout le monde va utiliser cette façon et l'intention du programmeur sera claire.
Cette règle a été écrite (à mon avis) en réaction à Perl qui a en effet le TMTOWTDI. Et côté Perl, je vois ça plus comme un constat qu'il existe mille et une façon de faire une tâche que comme quelque chose que le créateur de langage a volontairement instillé dans la conception.
Tu n'a pas réagi sur mon exemple pourtant ? C++, c'est pas le langage où quand on veut faire une classe copiable, il faut définir 4 méthodes différentes ? Mais pas de boiler-plate hein ?
Les constructions nouvelles du langage apportées dans C++11 et consorts sont certainement bien pratiques, mais dans les faits, elles sont très récentes dans l'histoire du langage (si on prend 1985 comme date de première visibilité, on est à 34 ans d'existence alors que le C++11 n'est là que depuis 8 ans). Elles restent encore peu connues, apportent leurs propres problèmes de lisibilité et de compréhension. Côté lisibilité, on repassera. Ça ajoute en plus énormément à la complexité du langage.
[^] # Re: Expressivité
Posté par barmic . Évalué à 3. Dernière modification le 25 mars 2019 à 16:56.
Les différentes structures proches, mais ayant potentiellement une sémantique (au sens de notre lecture du programme et pas au sens de la manière dont il est interprété par son compilateur) aide le développeur à exprimer ce qu'il souhaite représenter. Une condition, ça peut permettre d'exprimer des cas d'erreur, de gérer des valeurs par défaut (qui ne sont pas des erreurs), peuvent remplacer du polymorphisme,… on peut trouver tout un tas de sémantiques différentes. D'un point de vu purement machine ça reste un saut conditionnel, mais pour notre compréhension il peut être utile d'avoir des représentations différentes. On peut trouver dans différents langages les
if
,unless
,switch
, l'opérateur ternaire, des opérateurs de déréférencement null-safe, du pattern matching, legiven
de perl est une sorte de pattern matching bizarre, bash a${identifiant:-defaultValue}
et d'autres, etc. Ce sont autant de constructions qui permette au développeur d'exprimer des choses différentes, alors qu'elles sont compilée (ou du moins compilables) en un simple saut conditionnel.En écrivant ce paragraphe, je crois me souvenir que c'est théorisé le lien existant ou non entre la complexité d'une langue et son expressivité.
C'est un exemple et pas un argument. Des exemples on peut en sortir une infinité qui vont montrer ce que l'on veut. Je ne vois pas comment établir quoi que ce soit à partir de simples exemples.
La question me semble plus intéressante qu'il n'y paraît. C'est quoi une classe copiable ? Faire une deep/shall copy ? On parle juste de copier la référence ? S'il s'agit juste de faire de la copie de référence comme la plupart des langages le font, tu n'a pas besoin de ces 4 méthode.
Après oui le C++ n'est pas le langage le plus concis qui existe (c'est ce que tu voulais me faire dire ?) et le python n'est pas le langage le plus verbeux (c'est l'autre truc que tu voulais me faire dire ?).
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 1.
Ok, je saisis mieux. Après, je comprends toujours pas en quoi ça range le C++ dans la catégorie des langages expressifs, il reste pour moi associé à un trucs très complexe avec des erreurs très très absconses (genre tu oublies de mettre un espace entre deux > >, tu pleures). Mais je salue les progrès faits ces dernières années, même si je ne peux pas en tirer partie dans mon entreprise (cf mon autre commentaire).
Concernant l'expressivité, après être passé du BASIC/Assembleur au Pascal, puis au C, puis au C++, puis au Python (avec un détour par Caml Light), j'ai eu l'impression de progresser à chaque étape à pas de géant en terme de correspondance "ce que j'ai dans la tête" et "comment je l'exprime dans le langage". Avec Python, je ne ressens plus aucune limitation d'expressivité, et c'est probablement pour cela que ton commentaire ne résonne pas plus que cela en moi. Je reste cependant conditionné par le langage et je saisis bien qu'un programmeur familier des langages fonctionnels purs sera certainement très frustré par le manque d'expressivité de Python en la matière.
Il existe certes des structures plus complexes ou plus élaborées comme le pattern matching en OCaml mais je n'en ressens pas le manque. Avec les années, je ressens aussi l'importance de garder le code dans la catégorie du "moyennement complexe" afin de rester intelligible. Si j'écris du code qui va être partagé entre plusieurs développeurs, plusieurs équipes, qui va vivre pendant plusieurs années, je sais que je suis réticent à utiliser des constructions très puissantes du langage car je ne suis pas sur d'être lisibles pour mes collègues, ou même pour moi dans 10 ans.
Oui :-)
Tu y as mis du temps !
Aussi oui.
C'est surtout que ce que tu as écris est à l'exact opposé de mon ressenti sur ces deux langages. Je suis assez ébahi qu'on puisse avoir des expériences aussi éloignées. Sois tu as tort, sois …. il y a une autre explication (non, je n'ai pas tort :-) ).
C'est vrai que quand j'y pense, une grande partie de mes classes en C++ sont soit des "Plain Old Data" copiables par copie simple, soit des trucs plus complexes mais déjà gérés par la lib que j'utilises (Qt, boost, etc).
C'est juste que je me rappelle du gros warning que j'ai eu lors de l'apprentissage du langage sur les copies de classes.
[^] # Re: Expressivité
Posté par barmic . Évalué à 2.
Tu décrit très bien la complexité qui vient avec l'augmentation de l'expressivité. Et là j'ai parlé de constructions syntaxiques des langages mais tu as aussi le typage qui joue un rôle.
Et oui il faut faire attention, ces constructions peuvent aussi être très mal utilisées, ce qui rend un code inutilement complexe (augmente fortement la métrique wtf).
Go et python sont 2 bons exemples de langages qui veulent être simple. Ils tentent de pousser les gens vers des bonnes pratiques sans les perdre dans des miriades de concepts. Mais go 2 sera déjà un peu plus complexe il me semble avec entre autre de la généricité.
[^] # Re: Expressivité
Posté par rewind (Mastodon) . Évalué à 10.
Tu nous fais un bel homme de paille. Les gens sérieux qui font du C++ utilisent tous C++11 de nos jours (GCC utilise par défaut C++14, tout comme Clang, et même MSVC utilise du C++ moderne par défaut). Les nouvelles fonctionnalités apportent non seulement de la lisibilité, mais également des constructions nécessaire pour faire du code performant (comme la sémantique de déplacement). Tu peux refuser de les considérer mais tu passes à côté de l'essentiel quand tu fais du C++.
Et en C++11, pour qu'une classe soit copiable, il faut définir… bah rien ! Ça s'appelle la «rule of zero» qui dit qu'hormis les cas très particuliers de classes qui gèrent des ressources (et donc, qui doivent gérer à la main des problèmes d'«ownership»), les autres (95%) n'ont strictement rien à faire pour avoir les constructeurs par copie/déplacement et les opérateurs d'affectation par copie/déplacement et le destructeur gratos.
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 3.
C'est quoi la définition de sérieux ? Si je prends mon entreprise, où on parle quand même de développeurs qui gagnent leur vie en écrivant du code … on peut penser qu'il s'agit de gens sérieux non ? Et pourtant, côté C++, on est loin du C++11. Je pense même pas que la plupart des mes collègues immédiats connaissent le sigle. Si je leur montre un bout de code avec des lambdas et des templates, ils ne comprendront juste rien. On fait de la carte programmation pour carte à puce, ce qui veut dire beaucoup de C, un peu d'assembleur, un peu de JavaCard, et un peu de Python pour nos tests.
Aujourd'hui un collègue développeur a vu mon écran et m'a demandé pourquoi je regardais un forum sur le jeu de Go. Il n'avait jamais entendu parlé du langage…
On utilise un peu de Python mais le seul qui est installé sur leurs postes, c'est Python 3.1 . Et je ne m'avance pas à utiliser des syntaxes avancées de Python (décorateurs, getter/setters, comprehensions, …) si je ne veux pas les perdre en route.
Je tiens donc à souligner la grande distance qu'il y a entre des passionnés qui suivent les évolutions de l'informatique et des entreprises qui restent avant tout consommatrices d'outils en l'état.
Côté Visual Studio, on utilise la version … 2011 Professional. Et je crois pas que C++11 soit bien supporté dans cette version. :-)
Il y a pas de refus de ma part. C'est juste que le C++, globalement, je ne l'utilise pas. Et je sais que c'est un langage complexe, dont la complexité ne fait que grandir au cours du temps.
Déjà, j'avais noté que le C++ de mon époque était plus complexe que ce que mon cerveau pouvait encaisser en une seule fois. Je sais que je ne me hasarderai pas à lever une exception en C++ sans relire un bouquin entier sur le sujet tellement il y a de façon de mal le faire.
Alors maintenant, de savoir que la complexité du langage a augmenté (ce que je vois quand je lis des exemples dans quelques journaux, je comprends juste rien), ça me motive pas vraiment à m'y mettre. Après, si j'avais un boulot qui l'exige, je me lancerai à fond dedans avec plaisir.
Paradoxalement, j'ai fait pas mal de Qt/C++. Et je bénis Trolltech/Nokia/Digia/Qt d'avoir rendu le C++ utilisable même par des gens peu experts en la matière.
[^] # Re: Expressivité
Posté par Tarnyko (site web personnel) . Évalué à 2.
Ces gens ne se tiennent visiblement pas du tout au courant.
Ils peuvent être "appliqués", mais "sérieux" ?
En contexte fermé (vase clos) ils peuvent être considérés comme tels.
En contexte ouvert (contributif) ils seront poussés vers le bas.
[^] # Re: Expressivité
Posté par rewind (Mastodon) . Évalué à 5.
Ce n'est pas une histoire d'être passionné ou pas, c'est une histoire de faire évoluer ses outils pour pouvoir bénéficier des avancées qu'ils proposent. Ce n'est pas propre à l'informatique, c'est comme ça partout. C'est juste plus facile en informatique puisque les outils sont pour la plupart logiciels (c'est moins contraignant que de changer de machine-outil).
Effectivement, mais le problème ici, ce n'est pas le langage, c'est l'âge de l'outil qui est utilisé. Neuf ans en informatique, c'est une génération voire plus. Depuis 2011, Debian a sorti quatre versions !
Tu ne l'utilises pas mais tu sais. En fait, tu crois savoir et tu répètes des choses que tu as entendu dans les couloirs sans jamais avoir fait l'effort de te mettre dedans pour avoir ton propre avis.
La complexité du langage n'a pas augmenté, il y a juste des nouvelles fonctionnalités, comme dans beaucoup d'autres langages qui évoluent. Et tu n'as juste pas pris le temps de comprendre. Ce n'est pas un problème du langage (parce que plein de personnes ont pris ce temps et trouvent que finalement, c'est bien pratique ces nouvelles fonctionnalités), c'est un problème de ton envie par rapport à ce langage. Tu as le droit de ne pas l'utiliser, tu as le droit de te donner de mauvais argument, mais tu peux aussi admettre que ton avis n'est pas le plus éclairé pour parler de la complexité de ce langage, notamment dans ses versions les plus récentes.
[^] # Re: Expressivité
Posté par Philippe F (site web personnel) . Évalué à 2.
Perso, je partage plutôt le point de vue que c'est bien de se tenir à jour et de faire des outils plus performant et que ça va impacter de façon positive l'entreprise, la productivité, l'innovation, etc.
Par contre, objectivement, une entreprise qui a des outils qui lui donnent satisfaction n'a pas tant de raison que ça de s'intéresser à des nouvelles générations d'outils. Une petit citation pour la route : If it ain't broken, don't fix it - si ce n'est pas cassé, ne le répare pas.
Tu te trompes sur un point, c'est que j'ai fait l'effort de tenter de comprendre les nouveautés du C++. Je lis avec passion les articles de linuxfr qui en parlent, et j'ai lu la pages de nouveautés expliquée par … j'ai un doute, Herb Sutter ou Bjarne Soustroup (je ne retrouve pas le lien, je me souviens que c'était assez fouillé mais incomplet en tout cas). Il y a un certain nombre d'améliorations qui me parlent (la sémantique du move par exemple), d'autres où je saisis l'idée mais où j'ai du mal à rentrer dans les détails (les lambda, les constexpr) et d'autres où vraiment, c'est complètement au dessus de mon niveau de compréhension du langage.
On va avoir un débat sur le mot complexité vs quantité. On est au moins d'accord que la quantité de fonctionnalité augmente à chaque révision. Je maintiens que la complexité augmente aussi car il y a plus de façon de se tromper dans la façon d'écrire du code. Et il y a plus d'interactions possibles entre les nouvelles fonctionnalités.
[^] # Re: Expressivité
Posté par jyes . Évalué à 2.
… et c’est pour ça que mes collègues codent en Fortran 77. Elle est où la limite raisonnable à « pas tant de raison que ça » ? Sans complètement remettre en question ton propos, si les outils évoluent, c’est parce-que l’informatique évolue et, à un moment donné, refuser d’évoluer avec c’est vite être complètement largué. Dans ton exemple de Visual Studio 2011, je laisse les experts C++ juger de la raison de ce choix, personnellement, je n’aimerais pas travailler dans ces conditions.
Sur le reste de ton message, je trouve plutôt que les nouvelles versions de C++ limitent les façons de se tromper en proposant dans le langage et dans la STL des constructions plus simples et plus sûres qui n’ont de ce fait pas à être réimplémentées dans chaque programme (de manière différente en plus). Mais ça, c’est encore un avis très subjectif.
[^] # Re: Expressivité
Posté par jyes . Évalué à 4.
Pour avoir refait du C++ récemment, après une longue période sans (très appréciée), je dois avouer que mon avis sur ce langage a beaucoup évolué. Autant, je suis d’accord avec les critiques sur la complexité extrême et inutile des versions pré-C++11, autant de mon expérience avec du C++17 m’a été très agréable.
Je n’ai jamais trop compris les défenseurs du C++ à l’époque où je l’ai abandonné et ne comprends toujours pas ceux qui en utilisent des versions « anciennes », mais les dernières moutures prennent vraiment une tournure intéressante. Le seul truc qui me retient de l’utiliser pour des projets sérieux est la complexité de la compilation et un historique dont le langage n’est pas tout à fait remis, comme la dualité .h/.cpp qui n’apporte que de la confusion.
[^] # Re: Expressivité
Posté par Blackknight (site web personnel, Mastodon) . Évalué à 3.
Alors autant je trouve que le système hérité du C de header via le macro-processeur est pourri (oui, oui, on peut importer un .cpp dans un .h), autant je trouve indispensable de séparer l'interface de l'implémentation.
Du coup, je veux bien que tu m'expliques en quoi cela apporte de la confusion.
[^] # Re: Expressivité
Posté par barmic . Évalué à 3.
Factuellement, tu a un sacré paquets de développeurs qui arrivent à s'en dispenser ;)
[^] # Re: Expressivité
Posté par Blackknight (site web personnel, Mastodon) . Évalué à 2.
Oui, effectivement, j'en fais partie si tu parles du Java ou du Python :D
Mais ça ne veut pas dire que je trouve ça bien.
D'ailleurs, ça marche bien quand tu as accès aux sources dès que tu as du compilé sans les sources, c'est quand même mieux d'avoir des interfaces, non ? ;)
[^] # Re: Expressivité
Posté par jyes . Évalué à 4.
Oui, mais justement les .h du C++ ne sont pas des interfaces. Il contiennent par exemple l’implémentation complète des templates alors même que pour utiliser une bibliothèque compilée, les templates ne servent plus à rien : ont ne peut utiliser que ceux qui ont été explicitement construits et toute la machinerie d’automatisation qui va avec est perdue.
La frontière .h/.cpp actuelle n’est vraiment qu’un reliquat historique, et C++ ne sépare pas bien du tout les interfaces des implémentations, à l’inverse de ce qui se fait dans d’autres langages. Pour parler de ce que je connais, par exemple, l’avant et l’après « contains » d’un module Fortran.
[^] # Re: Expressivité
Posté par Blackknight (site web personnel, Mastodon) . Évalué à 3.
Là, je ne comprends pas (ceci dit, je n'ai plus fait de C++ depuis 15 ans alors c'est normal). Typiquement, la STL regorge de définitions de templates qu'on peut utiliser en les instanciant dans son propre code. Du coup, je veux bien un petit exemple :)
Et moi des packages et des package body en Ada
[^] # Re: Expressivité
Posté par rewind (Mastodon) . Évalué à 5.
La STL est presque complètement définie dans des .h, pas dans la bibliothèque, justement à cause des templates.
Petit exemple, imaginons que j'ai une classe template dans un .h
Après avoir écrit ça, j'ai alors deux choix pour implémenter les deux méthodes : soit les mettre dans le .h, soit les mettre dans le .cc (ou .cpp suivant les crémeries). Si tu les mets dans le .h, tu pourras instancier
Foo
avec n'importe quel type puisque tu auras accès aux définitions des méthodes (pas juste leur déclaration). Si tu les mets dans le .cc, tu ne pourras instancier que ce que le concepteur de la lib aura lui même instancié explicitement parce que tu n'auras pas accès aux définitions.Après, si tu mets les définitions dans le .h, tu peux soit les mettre directement dans la classe, soit séparément après la déclaration de la classe et même parfois dans un fichier à part (parfois suffixé .inl) que tu inclueras dans ton .h.
[^] # Re: Expressivité
Posté par Blackknight (site web personnel, Mastodon) . Évalué à 2.
Super, merci ! Maintenant, j'ai compris.
J'avoue n'avoir pas eu à faire ce genre de manip dans mon code C++ qui, au final, était majoritairement plus du C with classes écrit from scratch qu'autre chose.
Et du coup, les seuls templates que j'ai fait, c'étaient des génériques Java (sans interface) ou Ada (avec interfaces compilables).
# Principe de Pareto
Posté par anaseto . Évalué à 6.
Personnellement, je trouve que le langage Go est une assez bonne application du principe de Pareto : avec 20% de complexité/fonctionnalités ont obtient 80% d'expressivité.
Personnellement, j'ai rarement l'impression de souffrir d'un manque d'expressivité flagrant en programmant en Go, et pourtant je connais bien OCaml/Perl/Tcl et j'ai aussi fait du Haskell et du Lisp qui sont des langages très expressifs. La vérité, c'est que 95% du code qu'on écrit est en général plutôt trivial et n'utilise pas significativement des fonctionnalités plus avancées que celles trouvées dans Go (une boucle for ou un
map
ou unfold
, dans 95% des cas, ça représente une charge cognitive plus ou moins identique). Pour le 5% restant (je dirais souvent moins, mais bon), qu'on fasse de façon plus ou moins élégante et verbeuse, n'a finalement que rarement de l'importance. Oui, manipuler un AST ou écrire certains algorithmes particuliers est plus facile en OCaml/Haskell, et oui, faire du SQLite avec Tcl est plus fluide, ainsi que faire des petits scripts pour manipuler des chaînes est plus rapide en Perl, mais au final, ces choses représentent rarement une partie significative d'un programme fini (il y a des exceptions, j'ai utilisé Tcl pour faire programme de flashcards, par exemple, car c'était à 90% des requêtes SQL, mais ça reste un petit programme).Bref, toutes ces guerres pour dire que tel ou tel langage généraliste est plus ou moins expressif et/ou offre le meilleur de l'OO, du fonctionnel ou autre me laissent assez froid, car sauf aller vers le bas niveau (genre C), c'est rarement le manque de fonctionnalités du langage en soi qui va influencer significativement la productivité.
Par contre, 20% de complexité dans le langage plutôt que 100%, ça a beaucoup d'avantages : ça simplifie le compilateur (donc les temps de compilation, la création d'outils pour analyser le code, etc.); ça rend le langage plus facile à apprendre, ce qui est déjà bien en soi mais, en plus, attire une communauté plus intéressée par le résultat (ce que doit faire le programme final), plutôt que le cheminement (l'élégance du code et le perfectionnement de soi). La philosophie d'une communauté est quelque chose qui au final se voit partout, dans l'API des diverses bibliothèques, dans la documentation (faite pour le commun des mortels), etc., et ce sont des choses a priori que peu dépendantes du langage en soi et qui, pourtant, semblent être en pratique très influencées, du fait du public attiré et des divergences au niveau de ses objectifs.
[^] # Re: Principe de Pareto
Posté par barmic . Évalué à 2.
Si tu parle pour moi il n'est pas question de guerre, mais d'expliquer la dichotomie1. Au contraire je ne cherche pas particulièrement à dire que l'un est meilleur que l'autre. Si mes tournures l'ont fait penser c'est une mécompréhension tout à fait involontaire.
les langages cités (même si certains semblent particulièrement chatouilleux…) n'étaient là qu'à titre d'exemple sans pour autant être plus réfléchis que ça ↩
[^] # Re: Principe de Pareto
Posté par anaseto . Évalué à 3.
Je disais ça plutôt en général, car ces questions de manque d'expressivité de langage et manque de certaines fonctionnalités se soulèvent assez souvent concernant Go (pas qu'ici sur linuxfr), je ne visais pas un commentaire particulier, j'aurais été explicite et répondu au bon endroit si ça avait été le cas :-)
# Merci beaucoup pour cette traduction.
Posté par Kwiknclean . Évalué à 5.
Le Go est un langage qui me tente, je viens aussi de la famille Perl/PHP (que j'aime beaucoup) et à l'école (il y a longtemps maintenant) j'aimais beaucoup le C, je n'ai malheureusement pas eu l'occasion d'en refaire depuis.
Je n'ai que peut de connaissances POO (j'ai les connaissances mais pas de vraie compétences sur des projets), je n'ai jamais fait beaucoup de JAVA (qui avait la réputation d'être infrastructure killer) et je suis plutôt Infra / Sys et un obsédé de la performance, pas besoin de beaucoup de POO dans ce monde.
Je n'ai jamais été passionné, par Python, je l'ai pratiqué un peu, mais à mon sens et pour mes usages ce dernier n'apporte pas grand chose de plus que Perl, hormis plus d'objets. Bref j'ai toujours réussi à tout faire en Perl de façon rapide et efficace. Et j'aime l'obscure Perl je dois l'avouer, je suis un vilain :O
Mais c'est vrai que lorsqu'on veut partir dans des choses plus touchy comme le multi-canal ou le mutli-thread le forking ça se complique un peu, enfin ça devient lourd. Et je pense que Go me simplifierai bien la tâche.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.