In Scala, possiamo utilizzare almeno due metodi per aggiornare i tipi esistenti o nuovi. Supponiamo di voler esprimere che qualcosa può essere quantificato usando un Int
. Possiamo definire il seguente tratto.
Conversione implicita
trait Quantifiable{ def quantify: Int }
E poi possiamo usare conversioni implicite per quantificare ad esempio stringhe ed elenchi.
implicit def string2quant(s: String) = new Quantifiable{
def quantify = s.size
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{
val quantify = l.size
}
Dopo averli importati, possiamo chiamare il metodo quantify
su stringhe ed elenchi. Si noti che l'elenco quantificabile memorizza la sua lunghezza, quindi evita il costoso attraversamento dell'elenco nelle chiamate successive a quantify
.
Tipo di classi
Un'alternativa è definire un "testimone" Quantified[A]
che dichiari che un certo tipo A
può essere quantificato.
trait Quantified[A] { def quantify(a: A): Int }
Forniamo quindi istanze di questo tipo di classe per String
e List
da qualche parte.
implicit val stringQuantifiable = new Quantified[String] {
def quantify(s: String) = s.size
}
E se poi scriviamo un metodo che deve quantificare i suoi argomenti, scriviamo:
def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) =
as.map(ev.quantify).sum
O usando la sintassi del contesto:
def sumQuantities[A: Quantified](as: List[A]) =
as.map(implicitly[Quantified[A]].quantify).sum
Ma quando utilizzare quale metodo?
Ora arriva la domanda. Come posso decidere tra questi due concetti?
Quello che ho notato finora.
classi di tipo
- le classi di tipo consentono la bella sintassi legata al contesto
- con le classi di tipo non creo un nuovo oggetto wrapper ad ogni utilizzo
- la sintassi legata al contesto non funziona più se la classe di tipo ha più parametri di tipo; immagina di voler quantificare le cose non solo con numeri interi ma con valori di qualche tipo generale
T
. Vorrei creare una classe di tipoQuantified[A,T]
conversione implicita
- poiché creo un nuovo oggetto, posso memorizzare nella cache i valori o calcolare una rappresentazione migliore; ma dovrei evitarlo, poiché potrebbe accadere più volte e una conversione esplicita verrebbe probabilmente invocata solo una volta?
Cosa mi aspetto da una risposta
Presenta uno (o più) casi d'uso in cui la differenza tra i due concetti è importante e spiega perché preferirei uno rispetto all'altro. Anche spiegare l'essenza dei due concetti e la loro relazione reciproca sarebbe bello, anche senza esempio.
size
di una lista in un valore e dire che evita l'attraversamento costoso della lista per le chiamate successive per quantificare, ma di ogni vostra chiamata al quantify
l' list2quantifiable
viene attivato tutto da capo reinstanziando così Quantifiable
la quantify
proprietà e ricalcolando la proprietà. Quello che sto dicendo è che in realtà non c'è modo di memorizzare nella cache i risultati con conversioni implicite.