Por que é definido imutável de Scala não covariantes em seu tipo?
-
21-08-2019 - |
Pergunta
Editar : Re-escrito esta questão com base na resposta original
A classe scala.collection.immutable.Set
não é covariante em seu parâmetro de tipo. Por que é isso?
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
}
Solução
Set
é invariante em seu parâmetro de tipo por causa do conceito por trás conjuntos como funções. As assinaturas a seguir deve esclarecer as coisas um pouco:
trait Set[A] extends (A=>Boolean) {
def apply(e: A): Boolean
}
Se Set
eram covariant em A
, o método apply
seria incapaz de tomar um parâmetro do tipo A
devido à contravariance de funções. Set
poderia ser contravariant em A
, mas isso também causa problemas quando você quer fazer coisas como esta:
def elements: Iterable[A]
Em suma, a melhor solução é manter as coisas invariável, mesmo para a estrutura de dados imutáveis. Você notará que immutable.Map
também é invariante em um de seus parâmetros de tipo.
Outras dicas
em http://www.scala-lang.org/node/9764 Martin Odersky escreve:
"Sobre a questão de conjuntos, acredito que o não-variação decorre também das implementações. Conjuntos comuns são implementados como tabelas de hash, que são matrizes não-variantes do tipo de chave. Concordo que é uma irregularidade ligeiramente irritante."
Assim, parece que todos os nossos esforços para construir uma razão de princípios para este foram equivocados: -)
Editar : para qualquer um se perguntando por que esta resposta parece um pouco off-topic, isso é porque eu (o inquiridor) ter modificado a questão.
inferência de tipos do Scala é bom o suficiente para descobrir o que você quer CharSequences e não Cordas em algumas situações. Em particular, as seguintes obras para mim em 2.7.3:
import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")
Quanto à forma de criar immutable.HashSets diretamente: não. Como uma otimização de implementação, immutable.HashSets de menos de 5 elementos não são na verdade casos de immutable.HashSet. Eles são ou emptyset, Set1, Set2, Set3, ou Set4. Essas classes de subclasse immutable.Set, mas não immutable.HashSet.