Dans Scala, nous pouvons utiliser au moins deux méthodes pour moderniser des types existants ou nouveaux. Supposons que nous voulions exprimer que quelque chose peut être quantifié en utilisant un Int
. Nous pouvons définir le trait suivant.
Conversion implicite
trait Quantifiable{ def quantify: Int }
Et puis nous pouvons utiliser des conversions implicites pour quantifier par exemple les chaînes et les listes.
implicit def string2quant(s: String) = new Quantifiable{
def quantify = s.size
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{
val quantify = l.size
}
Après les avoir importés, nous pouvons appeler la méthode quantify
sur des chaînes et des listes. Notez que la liste quantifiable stocke sa longueur, ce qui évite la traversée coûteuse de la liste lors des appels ultérieurs à quantify
.
Classes de type
Une alternative est de définir un «témoin» Quantified[A]
qui déclare qu'un certain type A
peut être quantifié.
trait Quantified[A] { def quantify(a: A): Int }
Nous fournissons ensuite des instances de cette classe de type pour String
et List
quelque part.
implicit val stringQuantifiable = new Quantified[String] {
def quantify(s: String) = s.size
}
Et si on écrit ensuite une méthode qui a besoin de quantifier ses arguments, on écrit:
def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) =
as.map(ev.quantify).sum
Ou en utilisant la syntaxe liée au contexte:
def sumQuantities[A: Quantified](as: List[A]) =
as.map(implicitly[Quantified[A]].quantify).sum
Mais quand utiliser quelle méthode?
Vient maintenant la question. Comment puis-je choisir entre ces deux concepts?
Ce que j'ai remarqué jusqu'à présent.
classes de type
- les classes de type permettent la belle syntaxe liée au contexte
- avec les classes de type je ne crée pas de nouvel objet wrapper à chaque utilisation
- la syntaxe liée au contexte ne fonctionne plus si la classe de type a plusieurs paramètres de type; imaginez que je veux quantifier les choses non seulement avec des entiers mais avec des valeurs d'un type général
T
. Je voudrais créer une classe de typeQuantified[A,T]
conversion implicite
- puisque je crée un nouvel objet, je peux y mettre en cache des valeurs ou calculer une meilleure représentation; mais dois-je éviter cela, car cela peut se produire plusieurs fois et une conversion explicite ne serait probablement invoquée qu'une seule fois?
Ce que j'attends d'une réponse
Présentez un (ou plusieurs) cas d'utilisation dans lesquels la différence entre les deux concepts est importante et expliquez pourquoi je préférerais l'un à l'autre. Expliquer également l'essence des deux concepts et leur relation l'un avec l'autre serait bien, même sans exemple.