2011-08-17 13 views
6

Mi piacerebbe derivare dall'immutabile Mappa di Scala. Essa è definita come tale:È possibile modificare la varianza di una classe base/tratto in Scala?

trait Map[A, +B] 

Purtroppo, la mia implementazione deve essere invarianti in B. Ho provato quanto segue, ma senza successo:

def +(kv : (A, B)) : MyMap[A, B] = { ... } 

override def +[B1 >: B](kv : (A, B1)) : MyMap[A, B1] = 
    throw new IllegalArgumentException() 

Forse c'è un trucco con @uncheckedVariance?

+1

Forse potresti usare una mappa membro invece di derivare? – Owen

+0

Inoltre, perché ha bisogno di essere invariato? Ho pensato (anche se non conosco molto Scala) l'unica volta che hai bisogno di invarianza è se può essere sia una fonte che un sink, ma le mappe sono immutabili quindi non può essere un sink. – Owen

+0

Voglio implementare una mappa bidirezionale. Non è un grosso problema se implemento Map e deleghiamo solo le due mappe interne che definiscono la mappatura in avanti e indietro, ma in questo caso ho bisogno di invarianza. –

risposta

1

Eliminare del tutto la covarianza sarebbe, naturalmente, non corretto e non consentito. Dato m: Map[A, String] e v : Any, è possibile eseguire val mm : Map[A, Any] = m + v. Questo è ciò che dice la definizione Map e tutti gli implementatori devono seguire. La tua classe potrebbe essere invariata, ma deve implementare l'intera interfaccia covariante di Map.

Ora la ridefinizione di + per generare un errore è una storia diversa (non molto valida ancora). Il problema con il tuo nuovo metodo + è che dopo la cancellazione generica, ha la stessa firma dell'altro metodo +. C'è un trucco: aggiungi un parametro implicito, in modo da avere due parametri nella firma, il che lo rende diverso dal primo.

def +(kv : (A,B))(implicit useless: A <:< A) : MyMap[A,B] 

(non importa cosa implicita parametro che stai cercando, fino a quando uno si trova implicit useless: Ordering[String]. Funziona altrettanto bene)

Facendo questo, si ha il solito problema con sovraccarico . Se si aggiunge una B senza che il compilatore lo sappia, verrà chiamato il metodo fallito. Potrebbe essere meglio eseguire un controllo del tipo in modo che le istanze B siano accettate in qualsiasi modo. Ciò richiederebbe un Manifesto [B] nella tua mappa.

3

Il problema è che se si ottiene una versione invariabile da una mappa immutabile, si interromperà la sicurezza del tipo. Per esempio:

val dm = DiotMap(1 -> "abc") 
val m: Map[Int, Any] = dm 

Questa dichiarazione è valida, perché Map è covariante. Se la tua raccolta non è in grado di gestire la covarianza, cosa succede quando utilizzo m?

Problemi correlati