Cette sémantique particulière prend place exactement entre les sémantiques de valeur et d'entité dont elle recouvre certaines de leur caractéristiques, mais présente également certaines particularités qui lui sont propres :
Contradiction entre: elle prend place "exactement entre" mais elle "recouvre certaines de leurs caractéristiques", c'est soit l'un soit l'autre si on s'exprime rigoureusement
il est possible qu'elle soit destinée à servir dans une relation d'héritage, tout comme il est possible qu'elle ne le soit pas
soit A, soit non A: soit c'est une tautologie soit cela veut dire qu'il n'y a pas de règle concernant la participation à l'héritage. Pourtant, la plupart des conteneurs de la STL sont destinés à ne pas servir dans une relation d'héritage, ce qui contrevient plutôt à cette définition (ne pas à être destiné à être A != être destiné à ne pas être A)
elle fournit généralement la possibilité d'ajouter, de rechercher et de supprimer un (ou plusieurs) élément(s) particulier
ce qui m'embête avec le "généralement" c'est qu'il n'a généralement (
) pas sa place dans une définition, c'est plutôt un commentaire, parce qu'il ne permet pas de classer avec certitude dans ou hors d'une catégorie.
elle fournit au minimum la possibilité d'accéder en lecture seule à un élément particulier parmi ceux qu'elle contient
Ce qui est vrai de presque tous les objets composites, même de ceux à qui on ne donnerait pas spontanément le titre de collection. Un point x, y est il une collection de l'ordonnée et de l'abscisse?
elle peut fournir la possibilité d'accéder à un élément particulier parmi celle qu'elle contient afin de modification
on en revient à "la possibilité d'ajouter, de rechercher et de supprimer" puisque modifier équivaut à insérer après modification un élément retiré, non?
Dans la STL, le concept de conteneur est couplé au concept d'itérateur
Il y a quand même le bitset qui échappe à cette règle, non? Plus généralement conteneur != collection, puisque pair et tuple sont clairement des collections et pas des conteneurs
Quelques remarques de mon cru:
- le concept de collection est à mon avis étranger au C++. Le choix de la STL c'est justement de découpler les conteneurs et les algorithmes en plaçant les itérateurs au milieu. La généralisation de l'itérateur serait plutôt la séquence (range: cf Alexandrescu on iteration http://www.informit.com/articles/article.aspx?p=1407357 , si on est d'accord avec lui).
- dans la conception C++/STL, une collection pourrait être du point de vue conceptuel, c'est-à-dire de l'algorithme, tantôt une valeur "insécable" tantôt un "iterable": une matrice est un bon exemple puisque l'algorithme de multiplication la verra comme une paire d'itérateurs (sur des itérateurs, c'est la nature de matrice[i][j] par exemple) mais un algorithme générique comme le GCD ou la puissance la verrait comme l'élément d'un demi-groupe ou d'un demi-anneau. Il me semble donc qu'elle ne constitue pas une sémantique à part entière.
- en revanche, la classification des itérateurs qui est faite dans la STL pèche d'un point de vue sémantique (cf confusion entre la sémantique d'accès et la sémantique de déplacement qui devrait être découplée, comme c'est fait dans Boost::iterator), ce serait plutôt dans cette direction qu'une FAQ devrait informer des risques contenus dans la dangereuse proximité lexicale entre forward_iterator et input_iterator par exemple
Au total, s'il fallait définir la collection pour qu'elle corresponde à l'intuition générale du concept, je dirais que c'est un contenant étranger à son contenu, dans le sens où un Point (x, y) n'est pas étranger à ses coordonnées mais qu'une paire (x, y) l'est. En C++, le sens que cela peut prendre est difficile à définir: par exemple: template <class T> using Point = std::pair<T, T>; ne crée qu'un alias, pas un type différent et on pourra continuer à utiliser std::pair à la seule condition que les deux éléments qu'elle contient soit de même type: il n'y a pas de support du langage pour discriminer la sémantique de collection et d'objet. En Haskell, par exemple on peut créer un nouveau type à partir d'un type existant avec newtype et les deux types (pourtant strictement identiques) ne seront plus substituables. On pourrait peut-être faire cela En C++ avec des enveloppes template du genre
1 2 3 4 5 6
| template <typename T>
struct New_type {
T value;
explicit New_type(const T& v) : value(v) {}
// constructeurs explicites ou deleted
explicit operator T() { return value; } |
};
mais je ne sais pas où cela pourrait mener
Partager