¿Por qué el conjunto inmutable de Scala no es covariante en su tipo?
set covariance (3)
EDITAR : volvió a escribir esta pregunta en base a la respuesta original
La clase scala.collection.immutable.Set
no es covariante en su parámetro de tipo. ¿Por qué es esto?
import scala.collection.immutable._
def foo(s: Set[CharSequence]): Unit = {
println(s)
}
def bar(): Unit = {
val s: Set[String] = Set("Hello", "World");
foo(s); //DOES NOT COMPILE, regardless of whether type is declared
//explicitly in the val s declaration
}
en http://www.scala-lang.org/node/9764 Martin Odersky escribe:
"Sobre el tema de los conjuntos, creo que la no varianza se deriva también de las implementaciones. Los conjuntos comunes se implementan como tablas hash, que son matrices no variantes del tipo de clave. Estoy de acuerdo en que es una irregularidad ligeramente molesta".
Entonces, parece que todos nuestros esfuerzos para construir una razón de principios para esto fueron equivocados :-)
Set
es invariante en su parámetro de tipo debido al concepto detrás de los conjuntos como funciones. Las siguientes firmas deberían aclarar un poco las cosas:
trait Set[A] extends (A=>Boolean) {
def apply(e: A): Boolean
}
Si Set
fuera covariante en A
, el método apply
no podría tomar un parámetro de tipo A
debido a la contravarianza de las funciones. Set
podría ser contravariante en A
, pero esto también causa problemas cuando quieres hacer cosas como esta:
def elements: Iterable[A]
En resumen, la mejor solución es mantener las cosas invariables, incluso para la estructura de datos inmutables. Notará que immutable.Map
también es invariable en uno de sus parámetros de tipo.
EDITAR : para cualquiera que se pregunte por qué esta respuesta parece ligeramente fuera de tema, esto se debe a que yo (el que pregunta) he modificado la pregunta.
La inferencia de tipo de Scala es lo suficientemente buena como para darse cuenta de que desea CharSecuencias y no cadenas en algunas situaciones. En particular, lo siguiente me funciona en 2.7.3:
import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")
En cuanto a cómo crear inmutable.HashSets directamente: no. Como una optimización de implementación, inmutable.HashSets de menos de 5 elementos no son en realidad instancias de inmutable.HashSet. Son EmptySet, Set1, Set2, Set3 o Set4. Estas clases subclase inmutable.Set, pero no inmutable.HashSet.