Et j'en passe bien d'autres. Tu peux bien évidement surcharger toi même le comportement si tu le désires, mais les comportement par défaut de Show, Serialize, Eq et Hashable me conviennent parfaitement. Je ne sais pas faire cela en C++. Note que ce n'est pas quelque chose écrit en dure dans le compilateur, tu es libre de crée toi même tes propres "classes" génériques (par contre c'est pas forcement là où haskell est beau ;)
Euh, non, le découpage en petites unités fonctionnelles est très présent en C++. C’est ce que tout le monde recommande aujourd’hui (loi de Déméter, à l’esprit de tous les devs c++ compétents). C’est parce qu’il y a deux fichiers que c’est « trop compliqué de créer un classe » ? C’est un problème d’environnement de dev dans ce cas, pas de langage.
Cela a beau être faisable, ce n'est pas ce qui est fait dans BEAUCOUP de base de code que j'ai observé (libre ou pas). Mais cela n'est pas le point.
Je ne parle pas de découper en petites unités fonctionnelles, heureusement, c'est la base. Je parle de faire autant de petites unités fonctionnelle qu'il existe de cas de figure, pour se garantir de ne pas mélanger des tortues et des rats.
Un exemple. Tu as un type template template <typename T> class Vector3 dont tu veux te servir pour representer des positions, des directions, des couleurs (dans différents espaces), avec différents opérations possibles. Plusieurs solutions, très souvent celle que je rencontre c'est d'utiliser la même classe pour representer tout cela. C'est ce que je reproche, car j'aimerais un type par possibilité pour éviter des opérations du genre point + couleur. Hors en C++ cela devient très vite lourd de crée un nouveau type qui ne fait que déléguer. (Note que pour ce problème tu peux t'en sortir facilement avec des types phantom, mais ce n'est pas toujours le cas).
Euh, non. Tu peux très bien mettre un type non default constructible dans un unique_ptr. Depuis c++11, on peut même dans un vector, suivant comment on l’utilise (tant qu’on n’utilise pas resize). En plus, comme on peut le defaulter quand ça a du sens, ce n’est franchement pas la mer à boire.
Tu ne peux pas mettre un non default constructible comme deleter de unique_ptr. (i.e.: le second argument du template), même dans le cas où ton unique ptr est default initialisé avec nullptr. Ce qui te force à crée un constructeur par défaut à ton deleter et à gérer ce cas. Ce n'est pas la mer à boire je te l'accorde ;)
À mettre en balance avec le fait que C++ offre un const vérifié statiquement. Bien utilisé, c’est beaucoup de bugs ou de prises de tête en moins.
Je suis d'accord avec toi. J'aurais aimé l'inverse, du const par défaut et un truc genre mutable pour ce qui peut changer.
Pour le reste de tes critiques, je suis assez d’accord (sauf le pattern matching dont je trouve qu’à part l’effet trocool, ça ne sert pas à grand chose).
Disons que sans type algébrique, le pattern matching ne sert en effet pas à grand chose. Mais quand tu as des types algébriques et un pattern matching en profondeur, il permet d'expliciter tous les cas à traiter, avec une garantie statique à la compilation que tu as bien tout traité et une grande lisibilité de code.
Mais la question qui est toujours en suspens, c’est quelle alternative à c++ ? Pour du dev jetable, plein. Pour un truc censé durer 10 ans (c’est pas si long que ça dans le domaine du développement logiciel), il y a c# et java, si on peut se permettre le GC. Sinon...
Je n'ai jamais prétendu proposer une alternative au C++, d'ailleurs, comme le disait, écrire du C++ c'est ce qui me paye et j'y trouve certain avantage (au c++, et aussi au fait que on me paye ;)
Je n'ai pas l’expérience pour te répondre sur la pérennité du truc. J'ai vraiment tendance à penser que des langages avec des outils de packaging comme ce que on trouve en Rust ou Haskell vont te permettre de rebuilder ton projet dans les même conditions dans 10 ans, alors que ressortir un projet C++ qui a 10 ans et essayer de le rebuilder, c'est toujours une horreur de cache cache avec les dépendances. Pour moi c'est aussi une grande faiblesse du C++, c'est que, sauf si ta recette de build inclue TOUTES les dépendances ainsi que le compilateur, tu n'es pas garanti d'avoir un build identique 6 mois plus tard.
[^] # Re: Donc pour résumer...
Posté par Guillaum (site web personnel) . En réponse à la dépêche C++17, Genèse d’une version mineure. Évalué à 7.
Attention, je me sers d'Haskell dans ce post pour donner des exemples, mais je ne veux pas me lancer dans un débat C++ versus un autre langage.
En haskell, un type
Squarequi peut s'afficher, se serializer, se comparer à un autre, tester l'égalité et se hasher.Et j'en passe bien d'autres. Tu peux bien évidement surcharger toi même le comportement si tu le désires, mais les comportement par défaut de Show, Serialize, Eq et Hashable me conviennent parfaitement. Je ne sais pas faire cela en C++. Note que ce n'est pas quelque chose écrit en dure dans le compilateur, tu es libre de crée toi même tes propres "classes" génériques (par contre c'est pas forcement là où haskell est beau ;)
Cela a beau être faisable, ce n'est pas ce qui est fait dans BEAUCOUP de base de code que j'ai observé (libre ou pas). Mais cela n'est pas le point.
Je ne parle pas de découper en petites unités fonctionnelles, heureusement, c'est la base. Je parle de faire autant de petites unités fonctionnelle qu'il existe de cas de figure, pour se garantir de ne pas mélanger des tortues et des rats.
Un exemple. Tu as un type template
template <typename T> class Vector3dont tu veux te servir pour representer des positions, des directions, des couleurs (dans différents espaces), avec différents opérations possibles. Plusieurs solutions, très souvent celle que je rencontre c'est d'utiliser la même classe pour representer tout cela. C'est ce que je reproche, car j'aimerais un type par possibilité pour éviter des opérations du genre point + couleur. Hors en C++ cela devient très vite lourd de crée un nouveau type qui ne fait que déléguer. (Note que pour ce problème tu peux t'en sortir facilement avec des types phantom, mais ce n'est pas toujours le cas).Tu ne peux pas mettre un non default constructible comme deleter de
unique_ptr. (i.e.: le second argument du template), même dans le cas où ton unique ptr est default initialisé avec nullptr. Ce qui te force à crée un constructeur par défaut à ton deleter et à gérer ce cas. Ce n'est pas la mer à boire je te l'accorde ;)Je suis d'accord avec toi. J'aurais aimé l'inverse, du const par défaut et un truc genre
mutablepour ce qui peut changer.Disons que sans type algébrique, le pattern matching ne sert en effet pas à grand chose. Mais quand tu as des types algébriques et un pattern matching en profondeur, il permet d'expliciter tous les cas à traiter, avec une garantie statique à la compilation que tu as bien tout traité et une grande lisibilité de code.
Je n'ai jamais prétendu proposer une alternative au C++, d'ailleurs, comme le disait, écrire du C++ c'est ce qui me paye et j'y trouve certain avantage (au c++, et aussi au fait que on me paye ;)
Je n'ai pas l’expérience pour te répondre sur la pérennité du truc. J'ai vraiment tendance à penser que des langages avec des outils de packaging comme ce que on trouve en Rust ou Haskell vont te permettre de rebuilder ton projet dans les même conditions dans 10 ans, alors que ressortir un projet C++ qui a 10 ans et essayer de le rebuilder, c'est toujours une horreur de cache cache avec les dépendances. Pour moi c'est aussi une grande faiblesse du C++, c'est que, sauf si ta recette de build inclue TOUTES les dépendances ainsi que le compilateur, tu n'es pas garanti d'avoir un build identique 6 mois plus tard.