web-dev-qa-db-ja.com

Scalaの不変セットがそのタイプで共変でないのはなぜですか?

[〜#〜] edit [〜#〜]:元の回答に基づいてこの質問を書き直しました

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
}
90
oxbow_lakes

Setは、関数としてのセットの背後にある概念のため、その型パラメーターは不変です。次の署名は、物事をわずかに明確にする必要があります。

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

SetAで共変である場合、関数の共変性のために、applyメソッドはタイプAのパラメーターを受け取ることができません。 Setは潜在的にcontravariant in Aである可能性がありますが、これも次のようなことをしたいときに問題を引き起こします。

def elements: Iterable[A]

要するに、最良の解決策は、不変のデータ構造であっても、物事を不変に保つことです。 immutable.Mapは、その型パラメーターの1つでも不変です。

54
Daniel Spiewak

at http://www.scala-lang.org/node/9764 Martin Oderskyは次のように書いています:

「セットの問題については、非分散は実装にも起因すると思います。一般的なセットは、キータイプの非分散配列であるハッシュテーブルとして実装されます。少し厄介な不規則性であることに同意します。」

したがって、これの原則的な理由を構築するための私たちのすべての努力は誤った方向に進んだようです:-)

51
Seth Tisue

[〜#〜] edit [〜#〜]:なぜこの回答が少し話題から外れているのか疑問に思っている人にとっては、これは私(質問者)が質問を変更したためです。

Scalaの型推論は、状況によっては文字列ではなくCharSequencesが必要であることを理解するのに十分です。特に、2.7.3では次のことがうまくいきます。

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

Immutable.HashSetsを直接作成する方法については、しないでください。実装の最適化として、5要素未満のimmutable.HashSetは、実際にはimmutable.HashSetのインスタンスではありません。それらは、EmptySet、Set1、Set2、Set3、またはSet4のいずれかです。これらのクラスはimmutable.Setをサブクラス化しますが、immutable.HashSetはサブクラス化しません。

6
Jorge Ortiz