Почему неизменяемое множество Скалы не ковариантно по своему типу? - PullRequest
88 голосов
/ 24 марта 2009

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

Класс 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 ]

53 голосов
/ 24 марта 2009

Set инвариантен в параметре типа из-за концепции, лежащей в основе множеств как функций. Следующие подписи должны немного прояснить ситуацию:

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

Если бы Set были ковариантными в A, метод apply не смог бы принять параметр типа A из-за контравариантности функций. Set потенциально может быть контравариантным в A, но это также вызывает проблемы, когда вы хотите сделать что-то вроде этого:

def elements: Iterable[A]

Короче говоря, лучшим решением является сохранение неизменности даже для неизменяемой структуры данных. Вы заметите, что immutable.Map также инвариантен в одном из параметров своего типа.

49 голосов
/ 31 мая 2011

в http://www.scala -lang.org / node / 9764 Мартин Одерский пишет:

"Что касается набора, я полагаю, что не-дисперсия проистекает также из реализаций. Общие наборы реализованы в виде хеш-таблиц, которые являются не вариантными массивами типа ключа. Я согласен, что это немного раздражает неправильность." 1007 *

Итак, похоже, что все наши усилия по созданию принципиальной причины этого были ошибочными: -)

5 голосов
/ 24 марта 2009

РЕДАКТИРОВАТЬ : для всех, кто интересуется, почему этот ответ выглядит немного не по теме, это потому, что я (спрашивающий) изменил вопрос

Вывод типа Scala достаточно хорош, чтобы понять, что в некоторых ситуациях вам нужны CharSequence, а не Strings. В частности, у меня в 2.7.3 работает следующее:

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

Что касается того, как создать неизменяемый. Хэш-наборы напрямую: не надо. В качестве оптимизации реализации, immutable.HashSets из менее чем 5 элементов на самом деле не является экземплярами immutable.HashSet. Это либо EmptySet, Set1, Set2, Set3, либо Set4. Эти классы являются подклассами immutable.Set, но не неизменяемыми. HashSet.

...