2009-03-24 8 views
83

EDITAR: Re-escrito esta pregunta basada en respuesta original¿Por qué el conjunto inmóvil de Scala no es covariante en su tipo?

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 
} 
+0

Vale la pena señalar que 'foo (s.toSet [CharSequence]) 'compila bien. El método 'toSet' es O (1) - simplemente envuelve' asInstanceOf'. –

+1

Tenga en cuenta también que 'foo (Set (" Hello "," World "))' se compila también en 2.10, ya que Scala parece ser capaz de inferir el tipo correcto de conjunto. Sin embargo, no funciona con conversiones implícitas (http://stackoverflow.com/questions/23274033/implicit-definition-working-for-seq-but-not-for-set/). –

Respuesta

48

Set es invariable en su parámetro de tipo debido al concepto detrás de conjuntos como funciones. Las firmas siguientes deben aclarar las cosas un poco:

trait Set[A] extends (A=>Boolean) { 
    def apply(e: A): Boolean 
} 

Si Set fueron covariante en A, el método apply sería incapaz de tomar un parámetro de tipo A debido a la contravarianza de funciones. Set podría ser potencialmente contravariant en A, pero esto también provoca problemas cuando se quiere 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.

+4

) Supongo que este argumento gira en torno a "el concepto detrás de los conjuntos como funciones": ¿podría ampliarse esto? Por ejemplo, ¿qué ventajas tiene "un conjunto como función"? dame que un "conjunto como una colección" no? ¿Vale la pena perder el uso de ese tipo de covariante? –

+0

A la luz de tu respuesta, ¿(en general) * no * usarías Establecer como el tipo devuelto por una API?Normalmente tendría una implementación de servicio mantener un conjunto interno en Java, con la API de servicio envolver esto en una Colecciones. no modificable en un método de acceso. –

+0

Creo que haré una pregunta relacionada –

5

EDITAR: para cualquiera que se pregunte por qué esta respuesta parece un poco fuera de tema, esto se debe a que (el interrogador) he modificado la pregunta.

La inferencia de tipo de Scala es lo suficientemente buena como para descubrir que desea secuencias de caracteres y no cadenas en algunas situaciones. En particular, las siguientes obras para mí en 2.7.3:

import scala.collections.immutable._ 
def findCharSequences(): Set[CharSequence] = Set("Hello", "World") 

cuanto a cómo crear directamente immutable.HashSets: 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.

+0

Tienes razón; al tratar de simplificar mi ejemplo real cometí un error trivial: ( –

46

en http://www.scala-lang.org/node/9764 Martin Odersky escribe:

"Sobre la cuestión de conjuntos, creo que el no-varianza se deriva también de las implementaciones de conjuntos comunes se implementan como tablas hash, que son matrices no variante del. tipo de llave. Acepto que es una irregularidad ligeramente molesta ".

Por lo tanto, parece que todos nuestros esfuerzos para construir una razón de principio para este eran :-) equivocada

+1

Pero algunas secuencias también se implementan con matrices, y aún 'Seq' es covariante ... ¿Me falta algo? –

+2

Esto podría resolverse trivialmente almacenando 'Array [Any]' internamente. – rightfold

+0

@rightfold es correcto. Puede haber una razón razonable, pero esto no es así. –

Cuestiones relacionadas