2011-08-17 25 views
6

Me gustaría derivar del Mapa inmutable de Scala. Se define como tal:¿Es posible cambiar la varianza de una clase/rasgo base en Scala?

trait Map[A, +B] 

Por desgracia, mi aplicación tiene que ser invariantes en B. He intentado lo siguiente, pero sin éxito:

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

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

Tal vez hay un truco con @uncheckedVariance?

+1

¿Tal vez podría usar un mapa de miembros en lugar de derivar? – Owen

+0

Además, ¿por qué necesita ser invariante? Pensé (aunque no sé mucho Scala) la única vez que necesitas invarianza es si puede ser tanto una fuente como un receptor, pero los mapas son inmutables por lo que no puede ser un sumidero. – Owen

+0

Quiero implementar un mapa bidireccional. No es un gran problema si implemento Map, y simplemente delego a los dos mapas internos que definen el mapeo hacia adelante y hacia atrás, pero necesito la invarianza en ese caso. –

Respuesta

1

Deshacerse por completo de la covarianza sería, por supuesto, poco sólido y no está permitido. Dado m: Map[A, String], y v : Any, puede hacer val mm : Map[A, Any] = m + v. Esto es lo que dice la definición Map, y todos los implementadores deben seguir. Su clase puede ser invariante, pero debe implementar la interfaz covariante completa de Map.

Ahora redefinir + para arrojar un error es una historia diferente (no muy sonora todavía). El problema con su nuevo método + es que después del borrado de genéricos, tiene la misma firma que el otro método +. Hay un truco: agregue un parámetro implícito, para que tenga dos parámetros en la firma, lo que lo hace diferente del primero.

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

(que en realidad no importa cuál sea implícita parámetro que está buscando, siempre y cuando uno se encuentra implicit useless: Ordering[String]. Funciona igual de bien)

Haciendo eso, usted tiene el problema habitual con sobrecarga . Si agrega una B sin que el compilador lo sepa, se invocará el método que falla. Podría ser mejor realizar una verificación de tipo allí para que las instancias B sean aceptadas lo que sea. Eso requeriría obtener un Manifiesto [B] en su mapa.

3

El problema es que si obtiene una versión invariable de un mapa inmutable, romperá el tipo de seguridad. Por ejemplo:

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

Esta declaración es válida, porque es Map covariante. Si su colección no puede manejar la covarianza, ¿qué sucederá cuando use m?

Cuestiones relacionadas