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 quantifysu 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 Apuò essere quantificato.
trait Quantified[A] { def quantify(a: A): Int }
Forniamo quindi istanze di questo tipo di classe per Stringe Listda 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.
sizedi 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 quantifyl' list2quantifiableviene attivato tutto da capo reinstanziando così Quantifiablela quantifyproprietà e ricalcolando la proprietà. Quello che sto dicendo è che in realtà non c'è modo di memorizzare nella cache i risultati con conversioni implicite.