多くのOOPプログラミング言語では、型はco-、contra-またはin-バリアント。ほとんどの(これらの言語のすべてではないにしても)変数を所定の位置で変異させることができます。つまり、それらは完全に不変の言語ではありません。
私は this SO answer それ、Scala少なくとも、)で見たことはありません共変タイプは反変位置に現れることができ、反変タイプは共変位置に現れることができません。
この答え(そして実際、私がインターネットで見つけたすべての同様の例で)にある問題は、上記の事実の証拠を示すためにmutabilityに依存していることです。
だから私の質問は:
不変の環境では、分散の概念でさえ意味がありますか?
はい;サブタイプの存在は不変性とは無関係です。
投機的な完全に不変のすべての型OOP言語(すべての言語のように)は、それらが使用される場所に関係なく(つまり、関数の入力型/関数の出力型として)共変にできますか?
単純なデモンストレーションとして、関数の入力タイプを共変にすることができない理由を説明します(Scala構文を使用):
val f: Int => Int = x => 2 * x
val g: Any => Int = f // allowed by covariance
g("") // what should this do?
ルールは同じです:「プロデューサーは拡張(共変)、コンシューマースーパー(反変)」。そして、関数はその入力タイプのコンシューマーです。
分散は可変性とは何の関係もありません。これは、パラメトリック多型とサブタイピングの交点に表示されます。
最も古い分散の例は、実際には関数型プログラミングから生じる例です。つまり、質問:関数型が別の関数型のサブタイプになるのはいつですか?
そして、そのinputsが少なくとも一般的であり、そのoutputsが少なくともスーパータイプと同様に特定である場合、関数タイプは別の関数タイプのサブタイプであることがわかります。
言い換えると、関数は入力では反変、出力では共変です。
リスト/配列と比較関数を取り、ソートされたアイテムで新しい関数を返す関数があるとします。 Integersオブジェクトのリストがある場合、整数をソートできる関数compare(a,b)
が必要です。分散のないタイピングでは、関数が整数compare(a: Integer, a:Integer)
を取る必要があること、または関数が整数の特定のスーパータイプを取る必要があることを指定する必要があります。 compare(a: Object, a:Object)
。しかし、compare(a: Number, b: Number)
として定義された比較がある場合はどうなりますか?正常に動作するはずですが、どちらの場合も使用できません。したがって、比較関数がIntegerまたはIntegerの任意のsuperclassを処理できる必要があることを指定できる必要があります。つまり、逆分散です。