2009-09-10 14 views
23

mi sono chiesto se trasparentiimplicit conversioni sono davvero una buona idea e se potrebbe effettivamente essere meglio usare impliciti di più, um, esplicitamente. Ad esempio, supponiamo di avere un metodo che accetta un Date come parametro e ho una conversione implicita che trasforma un String in un Date:Scala scelte di utilizzo implicita

implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s) 

private def foo(d: Date) 

Poi ovviamente posso chiamare questo con un implicit conversione trasparente:

foo("20090910") 

Sarebbe meglio rendere il fatto che sto convertendo la stringa in una data più esplicita?

class DateString(val s: String) { 
    def toDate : Date = new SimpleDateFormat("yyyyMMdd").parse(s) 
} 

implicit def str2datestr(s: String) : DateString = new DateString(s) 

Allora l'utilizzo sembra più:

foo("20090910".toDate) 

Il vantaggio di questo è che è più chiaro in seguito ciò che sta accadendo - Sono stato preso fuori un paio di volte da trasparente implicit conversioni che dovrei sapere su (Option su Iterable chiunque?) e questo utilizzo ci consente comunque di sfruttare la potenza di implicit s.

risposta

43

Credo che il modo più "esplicito" di fare conversioni implicite sia molto migliore in termini di leggibilità rispetto a quello completamente trasparente, almeno in questo esempio.

A mio parere, utilizzando implicit s completamente trasparente dal tipo A di digitare B va bene quando si può sempre visualizzare un oggetto di tipo A come in grado di essere utilizzato ogni volta ed è necessario oggetto di tipo B. Ad esempio, la conversione implicita di String in un RandomAccessSeq[Char] ha sempre senso: un String può sempre essere considerato concettualmente come una sequenza di caratteri (in C, una stringa è solo una sequenza di caratteri, ad esempio). Una chiamata a x.foreach(println) ha senso per tuttiString s.

D'altra parte, le conversioni più espliciti deve essere usato quando un oggetto di tipo A può talvolta essere usato come un oggetto di tipo B. Nel tuo esempio, una chiamata a foo("bar") non ha senso e genera un errore. Poiché Scala non ha verificato le eccezioni, una chiamata a foo(s.toDate) segnala chiaramente che potrebbe essere generata un'eccezione (s potrebbe non essere una data valida). Inoltre, foo("bar".toDate) sembra chiaramente sbagliato, mentre è necessario consultare la documentazione per capire perché foo("bar") potrebbe essere sbagliato. Un esempio di questo nella libreria standard Scala conversioni da String s a Int s, tramite il metodo della RichString involucro toInt (String s può essere visto come Int s, ma non tutto il tempo).

13

Quando si effettua una conversione implicita da X a Y (come la conversione da Stringa a Data sopra), si sta essenzialmente dicendo che, se avessi il pieno controllo sulla scrittura di X in primo luogo, avresti fatto X implementare o essere una sottoclasse di Y.

Se per X è opportuno implementare Y, aggiungere la conversione. Se così non fosse, allora forse non è appropriato. Ad esempio, è logico che String implementi RandomAccessSeq [Char], ma forse non ha senso che String implementi Date (anche se l'implementazione String di StringDate sembra soddisfacente).

(Sono un po 'in ritardo, e Flaviu ha una risposta eccellente, ma volevo aggiungere un commento su come penso agli impliciti.)

Problemi correlati