L'utilisation de la version paramétrique donne
- Plus d'informations aux utilisateurs de la fonction
- Limite le nombre de programmes que vous pouvez écrire (vérification gratuite des bogues)
À titre d'exemple aléatoire, supposons que nous ayons une méthode qui calcule les racines d'une équation quadratique
int solve(int a, int b, int c) {
// My 7th grade math teacher is laughing somewhere
}
Et puis vous voulez qu'il fonctionne sur d'autres sortes de nombres comme des choses en plus int
. Vous pouvez écrire quelque chose comme
Num solve(Num a, Num b, Num c){
...
}
Le problème est que cela ne dit pas ce que vous voulez. Ça dit
Donnez-moi 3 choses qui sont comme des nombres (pas nécessairement de la même manière) et je vous donnerai une sorte de nombre
Nous ne pouvons pas faire quelque chose comme int sol = solve(a, b, c)
if a
, b
et c
sont int
s parce que nous ne savons pas que la méthode va retourner un int
à la fin! Cela conduit à des danses maladroites avec abattage et prière si nous voulons utiliser la solution dans une expression plus large.
À l'intérieur de la fonction, quelqu'un pourrait nous remettre un flotteur, un bigint et des degrés et nous devrions les ajouter et les multiplier ensemble. Nous aimerions rejeter statiquement cela parce que les opérations entre ces 3 classes vont être du charabia. Les degrés sont mod 360 donc ce ne sera pas le cas a.plus(b) = b.plus(a)
et des hilarités similaires se produiront.
Si nous utilisons le polymorphisme paramétrique avec le sous-typage, nous pouvons exclure tout cela parce que notre type dit réellement ce que nous voulons dire
<T : Num> T solve(T a, T b, T c)
Ou en mots "Si vous me donnez un type qui est un nombre, je peux résoudre des équations avec ces coefficients".
Cela se produit également dans de nombreux autres endroits. Une autre bonne source d'exemples sont des fonctions qui font abstraction sur une sorte de récipient, ala reverse
, sort
, map
, etc.