210 votes

Pourquoi la STL du C++ est-elle si fortement basée sur les modèles ? (et non sur les *interfaces*)

Je veux dire, à part son nom obligatoire (la bibliothèque standard de modèles)...

Le C++ avait initialement pour but de présenter les concepts de la POO en C. C'est-à-dire que vous pouviez dire ce qu'une entité spécifique pouvait et ne pouvait pas faire (indépendamment de la manière dont elle le fait) en vous basant sur sa classe et sa hiérarchie de classes. Certaines compositions de capacités sont plus difficiles à décrire de cette manière en raison des problèmes d'héritage multiple, et du fait que le C++ supporte le concept d'interfaces d'une manière quelque peu maladroite (comparé à Java, etc.), mais c'est là (et pourrait être amélioré).

Et puis les modèles sont entrés en jeu, ainsi que la STL. Le STL semblait prendre les concepts classiques de la POO et les jeter dans les égouts, en utilisant des modèles à la place.

Il faut distinguer les cas où les modèles sont utilisés pour généraliser des types où les types eux-mêmes ne sont pas pertinents pour le fonctionnement du modèle (les conteneurs, par exemple). Le fait d'avoir un vector<int> est parfaitement logique.

Cependant, dans de nombreux autres cas (itérateurs et algorithmes), les types gabarits sont censés suivre un "concept" (Input Iterator, Forward Iterator, etc...) où les détails réels du concept sont définis entièrement par l'implémentation de la fonction/classe du gabarit, et non par la classe du type utilisé avec le gabarit, ce qui est un peu un anti-usage de la POO.

Par exemple, vous pouvez dire à la fonction :

void MyFunc(ForwardIterator<...> *I);

Mise à jour : Comme il n'était pas clair dans la question originale, ForwardIterator est ok pour être templé lui-même pour permettre n'importe quel type de ForwardIterator. Le contraire est d'avoir ForwardIterator comme un concept.

s'attend à un forward Iterator uniquement en regardant sa définition, alors qu'il faudrait soit regarder l'implémentation, soit la documentation pour :

template <typename Type> void MyFunc(Type *I);

Deux arguments en faveur de l'utilisation des templates : le code compilé peut être rendu plus efficace, en compilant sur mesure le template pour chaque type utilisé, au lieu d'utiliser les vtables. Et le fait que les templates peuvent être utilisés avec des types natifs.

Cependant, je cherche une raison plus profonde pour laquelle abandonner la POO classique en faveur de la modélisation pour la STL (en supposant que vous ayez lu jusqu'ici :P).

598voto

jalf Points 142628

La réponse courte est "parce que le C++ a évolué". Oui, à la fin des années 70, Stroustrup avait l'intention de créer un C amélioré avec des capacités de POO, mais c'était il y a longtemps. Au moment où le langage a été normalisé en 1998, il ne s'agissait plus d'un langage POO. C'était un langage multi-paradigme. Il avait certainement un certain support pour le code POO, mais il était également recouvert d'un langage de modèle complet de Turing, il permettait la métaprogrammation à la compilation, et les gens avaient découvert la programmation générique. Tout à coup, la POO ne semblait plus si importante. Pas quand nous pouvons écrire des programmes plus simples, plus concis et plus efficaces. et un code plus efficace en utilisant les techniques disponibles grâce aux modèles et à la programmation générique.

La POO n'est pas le Saint Graal. C'est une belle idée, et c'était une amélioration par rapport aux langages procéduraux dans les années 70 quand ils ont été inventés. Mais honnêtement, ce n'est pas tout ce que l'on prétend. Dans de nombreux cas, il est maladroit et verbeux et il ne favorise pas vraiment le code réutilisable ou la modularité.

C'est pourquoi la communauté C++ est aujourd'hui beaucoup plus intéressée par la programmation générique, et pourquoi tout le monde commencent enfin à réaliser que la programmation fonctionnelle est également très intelligente. La POO toute seule n'est pas très belle à voir.

Essayez de dessiner un graphe de dépendance d'une hypothétique STL "OOP-ifiée". Combien de classes devraient connaître les autres ? Il y aurait un lot de dépendances. Pourriez-vous inclure seulement le vector sans obtenir également iterator ou même iostream tirée ? La STL rend cela facile. Un vecteur connaît le type d'itérateur qu'il définit, et c'est tout. Les algorithmes de la STL savent rien . Ils n'ont même pas besoin d'inclure un en-tête d'itérateur, même s'ils acceptent tous des itérateurs comme paramètres. Laquelle est la plus modulaire alors ?

La STL ne suit peut-être pas les règles de la POO telles que Java les définit, mais n'atteint-elle pas le but de la POO ? objectifs de la POO ? Ne permet-elle pas de réaliser la réutilisabilité, le couplage faible, la modularité et l'encapsulation ?

Et n'atteint-elle pas ces objectifs meilleur qu'une version OOP-ifiée ?

Quant à savoir pourquoi la STL a été adoptée dans le langage, plusieurs choses se sont produites qui ont conduit à la STL.

Tout d'abord, les modèles ont été ajoutés au C++. Ils ont été ajoutés pour la même raison que les génériques ont été ajoutés à .NET. Cela semblait être une bonne idée de pouvoir écrire des choses comme "conteneurs d'un type T" sans renoncer à la sécurité des types. Bien sûr, la mise en œuvre sur laquelle ils se sont arrêtés était beaucoup plus complexe et puissante.

Puis les gens ont découvert que le mécanisme de modèle qu'ils avaient ajouté était encore plus puissant que prévu. Et quelqu'un a commencé à expérimenter l'utilisation de modèles pour écrire une bibliothèque plus générique. Une bibliothèque inspirée par la programmation fonctionnelle et qui utilise toutes les nouvelles capacités du C++.

Il l'a présenté au comité du langage C++, qui a mis un certain temps à s'y habituer parce qu'il avait l'air si étrange et différent, mais qui s'est finalement rendu compte que cela fonctionnait mieux que les équivalents traditionnels de la POO qu'ils auraient dû inclure autrement. . Ils y ont donc apporté quelques modifications et l'ont adopté dans la bibliothèque standard.

Ce n'était pas un choix idéologique, ni un choix politique du type "voulons-nous être OOP ou non", mais un choix très pragmatique. Ils ont évalué la bibliothèque, et ont vu qu'elle fonctionnait très bien.

Dans tous les cas, les deux raisons que vous mentionnez pour favoriser la STL sont absolument essentielles.

La bibliothèque standard C++ a pour être efficace. S'il est moins efficace que, par exemple, le code C équivalent développé à la main, les gens ne l'utiliseront pas. Cela réduirait la productivité, augmenterait la probabilité d'apparition de bogues et serait tout simplement une mauvaise idée.

Et la STL a pour travailler avec des types primitifs, parce que les types primitifs sont tout ce que vous avez en C, et ils sont une partie importante des deux langages. Si la STL ne fonctionnait pas avec les tableaux natifs, elle serait inutile .

Votre question suppose fortement que la POO est "la meilleure". Je suis curieux de savoir pourquoi. Vous demandez pourquoi ils ont "abandonné la POO classique". Je me demande pourquoi ils auraient dû s'y tenir. Quels avantages aurait-elle eus ?

88voto

Tyler McHenry Points 35551

La réponse la plus directe à ce que je pense être votre question/plainte est la suivante : L'hypothèse selon laquelle le C++ est un langage OOP est une fausse hypothèse.

Le C++ est un langage multi-paradigme. Il peut être programmé en utilisant les principes de la POO, il peut être programmé de manière procédurale, il peut être programmé de manière générique (templates), et avec C++11 (anciennement connu sous le nom de C++0x) certaines choses peuvent même être programmées de manière fonctionnelle.

Les concepteurs du C++ voient cela comme un avantage, et ils soutiennent que le fait de contraindre le C++ à se comporter comme un langage purement POO lors de la programmation générique résout le problème mieux et, en fait, davantage. Généralement serait un pas en arrière.

73voto

Max Lybbert Points 11822

D'après ce que j'ai compris, Stroustrup préférait à l'origine une conception de conteneurs de type "OOP", et ne voyait en fait pas d'autre moyen de le faire. Alexander Stepanov est le responsable de la STL, et ses objectifs n'incluaient pas "le rendre orienté objet". :

C'est le point fondamental : les algorithmes sont définis sur des structures algébriques. Il m'a fallu encore deux ans pour comprendre qu'il fallait étendre la notion de structure en ajoutant des exigences de complexité aux axiomes réguliers. ... Je crois que les théories des itérateurs sont aussi centrales pour l'informatique que les théories des anneaux ou des espaces de Banach le sont pour les mathématiques. Chaque fois que je regardais un algorithme, j'essayais de trouver une structure sur laquelle il est défini. Ce que je voulais faire, c'était décrire les algorithmes de manière générique. C'est ce que j'aime faire. Je peux passer un mois à travailler sur un algorithme bien connu en essayant de trouver sa représentation générique. ...

STL, du moins pour moi, représente la seule façon de programmer. Elle est, en effet, très différente de la programmation C++ telle qu'elle a été présentée et est toujours présentée dans la plupart des manuels. Mais, voyez-vous, je n'essayais pas de programmer en C++, j'essayais de trouver la bonne façon de traiter les logiciels. ...

J'ai eu beaucoup de faux départs. Par exemple, j'ai passé des années à essayer de trouver une utilité à l'héritage et aux virtuels, avant de comprendre pourquoi ce mécanisme était fondamentalement défectueux et ne devait pas être utilisé. Je suis très heureux que personne n'ait pu voir toutes les étapes intermédiaires - la plupart d'entre elles étaient très stupides.

(Dans le reste de l'interview, il explique pourquoi l'héritage et les virtualités - alias la conception orientée objet - "étaient fondamentalement défectueux et ne devaient pas être utilisés").

Une fois que Stepanov a présenté sa bibliothèque à Stroustrup, ce dernier et d'autres ont déployé des efforts herculéens pour l'intégrer à la norme ISO C++ (même interview) :

Le soutien de Bjarne Stroustrup a été crucial. Bjarne voulait vraiment que STL fasse partie de la norme et si Bjarne veut quelque chose, il l'obtient. ... Il m'a même obligé à faire des changements dans STL que je n'aurais jamais fait pour quelqu'un d'autre... C'est la personne la plus déterminée que je connaisse. Il fait avancer les choses. Il lui a fallu un certain temps pour comprendre ce qu'était la STL, mais quand il l'a compris, il était prêt à faire avancer les choses. Il a également contribué à la STL en défendant l'idée que plus d'une façon de programmer était valable - contre vents et marées pendant plus d'une décennie, et en recherchant une combinaison de flexibilité, d'efficacité, de surcharge et de sécurité des types dans les modèles qui a rendu la STL possible. Je tiens à affirmer clairement que Bjarne est le concepteur de langage prééminent de ma génération.

24voto

StackedCrooked Points 12247

La réponse se trouve dans cette interview avec Stepanov, l'auteur de la STL :

Oui. La STL n'est pas orientée objet. I pense que l'orientation objet est presque autant un canular que l'artificialité. artificielle. Je n'ai pas encore vu un un morceau de code intéressant qui vienne de ces gens de l'OO.

18voto

AraK Points 38702

Pourquoi une conception purement POO d'une bibliothèque de structures de données et d'algorithmes serait-elle meilleure ? La POO n'est pas la solution pour tout.

À mon avis, la STL est la bibliothèque la plus élégante que j'aie jamais vue :)

pour votre question,

Vous n'avez pas besoin de polymorphisme d'exécution, c'est un avantage pour la STL de mettre en œuvre la bibliothèque en utilisant le polymorphisme statique, ce qui signifie l'efficacité. Essayez d'écrire un algorithme générique de tri, de distance ou autre qui s'applique à TOUS les conteneurs ! Votre tri en Java appellerait des fonctions qui sont dynamiques à travers n niveaux à exécuter !

Vous avez besoin de choses stupides comme le Boxing et l'Unboxing pour cacher les hypothèses désagréables des langages OOP soi-disant purs.

Le seul problème que je vois avec STL, et les modèles en général, ce sont les horribles messages d'erreur. Ce qui sera résolu en utilisant Concepts dans C++0X.

Comparer la STL aux collections en Java, c'est comme comparer le Taj Mahal à ma maison :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X