Il est communément admis que les génériques Java ont échoué de plusieurs manières importantes. La combinaison de caractères génériques et de limites a conduit à un code très illisible.
Cependant, quand je regarde d'autres langages, je n'arrive vraiment pas à trouver un système de type générique qui plaise aux programmeurs.
Si nous prenons les éléments suivants comme objectifs de conception d'un tel système de types:
- Produit toujours des déclarations de type faciles à lire
- Facile à apprendre (pas besoin de réviser la covariance, la contravariance, etc.)
- maximise le nombre d'erreurs de compilation
Y a-t-il une langue qui a bien fait les choses? Si je google, la seule chose que je vois est des plaintes sur la façon dont le système de type aspire dans la langue X. Ce type de complexité est-il inhérent à la frappe générique? Faut-il simplement renoncer à essayer de vérifier la sécurité du type à 100% au moment de la compilation?
Ma principale question est de savoir quel est le langage qui a "bien fait les choses" en ce qui concerne ces trois objectifs. Je me rends compte que c'est subjectif, mais jusqu'à présent, je ne peux même pas trouver une langue où tous les programmeurs ne conviennent pas que le système de type générique est un gâchis.
Addendum: comme indiqué, la combinaison de sous-typage / héritage et génériques est ce qui crée la complexité, donc je suis vraiment à la recherche d'un langage qui combine les deux et évite l'explosion de la complexité.
la source
easy-to-read type declarations
? Le troisième critère est également ambigu: par exemple, je peux transformer les exceptions d'index de tableau hors limites en erreurs de temps de compilation en ne vous laissant pas indexer les tableaux sauf si je peux calculer l'index au moment de la compilation. De plus, le deuxième critère exclut le sous-typage. Ce n'est pas nécessairement une mauvaise chose, mais vous devez être conscient de ce que vous demandez.Foo<T> where SiameseCat:T
) et qu'il n'y a aucune possibilité d'avoir un type générique qui ne soit pas convertible enObject
. À mon humble avis, .NET bénéficierait de types d'agrégats similaires aux structures, mais encore plus désossés. S'ilKeyValuePair<TKey,TValue>
s'agissait d'un tel type, alors unIEnumerable<KeyValuePair<SiameseCat,FordFocus>>
pourrait être converti enIEnumerable<KeyValuePair<Animal,Vehicle>>
, mais uniquement si le type ne pouvait pas être encadré.Réponses:
Bien que les génériques soient courants dans la communauté de la programmation fonctionnelle depuis des décennies, l'ajout de génériques aux langages de programmation orientés objet offre certains défis uniques, en particulier l'interaction du sous-typage et des génériques.
Cependant, même si nous nous concentrons sur les langages de programmation orientés objet, et Java en particulier, un système générique bien meilleur aurait pu être conçu:
Les types génériques devraient être admissibles partout où se trouvent d'autres types. En particulier, si
T
est un paramètre de type, les expressions suivantes doivent être compilées sans avertissement:Oui, cela nécessite la réification des génériques, comme tous les autres types de la langue.
La covariance et la contravariance d'un type générique doivent être spécifiées dans (ou déduites de) sa déclaration, plutôt que chaque fois que le type générique est utilisé, afin que nous puissions écrire
plutôt que
Comme les types génériques peuvent devenir assez longs, nous ne devrions pas avoir besoin de les spécifier de manière redondante. Autrement dit, nous devrions être en mesure d'écrire
plutôt que
Tout type doit être admissible en tant que paramètre de type, pas seulement les types de référence. (Si nous pouvons en avoir un
int[]
, pourquoi ne pouvons-nous pas en avoir unList<int>
)?Tout cela est possible en C #.
la source
L'utilisation de sous-types crée de nombreuses complications lors de la programmation générique. Si vous insistez pour utiliser un langage avec des sous-types, vous devez accepter qu'il y a une certaine complexité inhérente à la programmation générique qui l'accompagne. Certaines langues le font mieux que d'autres, mais vous ne pouvez pas aller plus loin.
Comparez cela aux génériques de Haskell, par exemple. Ils sont suffisamment simples pour que si vous utilisez l'inférence de type, vous pouvez écrire une fonction générique correcte par accident . En fait, si vous spécifiez un seul type, le compilateur dit souvent à lui - même: « Eh bien, j'été va faire ce générique, mais vous m'a demandé de le faire que pour ints, donc peu importe. »
Certes, les gens utilisent le système de type de Haskell de manière étonnamment complexe, ce qui en fait le fléau de chaque débutant, mais le système de type sous-jacent lui-même est élégant et très admiré.
la source
a
doit être une sorte d'entier".Il y a eu pas mal de recherches sur la combinaison des génériques avec le sous-typage il y a environ 20 ans. Le langage de programmation Thor développé par le groupe de recherche de Barbara Liskov au MIT avait une notion de clauses «où» qui vous permettent de spécifier les exigences du type sur lequel vous paramétrez. (Ceci est similaire à ce que C ++ essaie de faire avec les concepts .)
L'article décrivant les génériques de Thor et comment ils interagissent avec les sous-types de Thor est: Day, M; Gruber, R; Liskov, B; Myers, AC: Subtypes vs. where clauses: constraining parametric polymorphism , ACM Conf on Obj-Oriented Prog, Sys, Lang and Apps , (OOPSLA-10): 156-158, 1995.
Je crois qu'ils ont, à leur tour, construit sur le travail qui a été fait sur Emerald à la fin des années 1980. (Je n'ai pas lu ce travail, mais la référence est: Black, A; Hutchinson, N; Jul, E; Levy, H; Carter, L: Distribution and Abstract Types in Emerald , _IEEE T. Software Eng., 13 ( 1): 65-76, 1987.
Thor et Emerald étaient tous les deux des "langues académiques", donc ils n'ont probablement pas été suffisamment utilisés pour que les gens comprennent vraiment si les clauses (concepts) résolvent vraiment de réels problèmes. Il est intéressant de lire l'article de Bjarne Stroustrup sur les raisons de l'échec du premier essai de Concepts in C ++: Stroustrup, B: The C ++ 0x "Remove Concepts" Decision , Dr Dobbs , 22 juillet 2009. (Plus d'informations sur la page d'accueil de Stroustrup . )
Une autre direction que les gens semblent essayer est quelque chose appelé traits . Par exemple, le langage de programmation Rust de Mozilla utilise des traits. Si je comprends bien (ce qui peut être complètement faux), déclarer qu'une classe satisfait un trait est très similaire à dire qu'une classe implémente une interface, mais vous dites "se comporte comme un" plutôt que "est un". Il semble que les nouveaux langages de programmation Swift d'Apple utilisent un concept similaire de protocoles pour spécifier les contraintes sur les paramètres des génériques .
la source