Почему неизменяемое множество Скалы не ковариантно по своему типу?
РЕДАКТИРОВАТЬ: переписать этот вопрос на основе оригинального ответа
scala.collection.immutable.Set
класс не является ковариантным по своему параметру типа. Почему это?
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
}
3 ответа
Set
является инвариантным по своему параметру типа из-за концепции множеств как функций. Следующие подписи должны немного прояснить ситуацию:
trait Set[A] extends (A=>Boolean) {
def apply(e: A): Boolean
}
Если Set
были ковариантны в A
, apply
Метод не сможет принять параметр типа A
из-за противоречивости функций. Set
потенциально может быть противоречивым в A
, но это также вызывает проблемы, когда вы хотите сделать что-то вроде этого:
def elements: Iterable[A]
Короче говоря, лучшее решение состоит в том, чтобы сохранить вещи неизменными даже для неизменной структуры данных. Вы заметите, что immutable.Map
также инвариантен в одном из параметров своего типа.
На http://www.scala-lang.org/node/9764 Мартин Одерский пишет:
"Что касается набора, я считаю, что не-дисперсия проистекает также из реализаций. Общие наборы реализованы в виде хеш-таблиц, которые являются не вариантными массивами типа ключа. Я согласен, что это немного раздражает неправильность".
Таким образом, кажется, что все наши усилия по созданию принципиальной причины для этого были ошибочными:-)
РЕДАКТИРОВАТЬ: для тех, кто задается вопросом, почему этот ответ кажется немного не по теме, это потому, что я (спрашивающий) изменил вопрос.
Вывод типа Scala достаточно хорош, чтобы понять, что в некоторых ситуациях вам нужны CharSequence, а не Strings. В частности, в версии 2.7.3 у меня работает следующее:
import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")
Что касается того, как создать immutable.HashSets напрямую: не надо. В качестве оптимизации реализации immutable.HashSets из менее чем 5 элементов на самом деле не является экземплярами immutable.HashSet. Это или EmptySet, Set1, Set2, Set3 или Set4. Эти классы являются подклассами immutable.Set, но не immutable.HashSet.