Почему неизменяемое множество Скалы не ковариантно по своему типу?

РЕДАКТИРОВАТЬ: переписать этот вопрос на основе оригинального ответа

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.

Другие вопросы по тегам