(私のものを強調)
フィールドと関数の共変再定義には問題はありませんが、 引数の共変再定義は、不正な型が引数として渡される可能性があるという問題を引き起こします。
しかし、フィールドと関数の型を共変に再定義しても問題が発生しない場合、引数の型を共変に再定義すると問題が発生するのはなぜでしょうか?
共変再定義はサブタイプ化と同じですよね? サブタイプはスーパータイプに取って代わることができます!
キャッチは何ですか?
(私のものを強調)
フィールドと関数の共変再定義には問題はありませんが、 引数の共変再定義は、不正な型が引数として渡される可能性があるという問題を引き起こします。
しかし、フィールドと関数の型を共変に再定義しても問題が発生しない場合、引数の型を共変に再定義すると問題が発生するのはなぜでしょうか?
共変再定義はサブタイプ化と同じですよね? サブタイプはスーパータイプに取って代わることができます!
キャッチは何ですか?
問題は共分散そのものではありません。(特に、逆分散の場合、子孫クラスの機能の引数型は親で利用可能な機能を持つ必要がないため、契約による設計は不可能です。共分散では、そのような問題はありません。)
問題なのは、共分散とポリモーフィズムの組み合わせです。例えば
class A feature
foo (a: A) do a.bar end -- (1)
bar do end
end
class B inherit A redefine foo end feature
foo (a: B) do a.qux end -- (2)
qux do end
end
次のコードはクラッシュします。
a: A; b: B
...
create b
a := b
a.foo (create {A})
実際、はタイプ のオブジェクトにアタッチされているa.foo
ため、バージョン (2) を呼び出します。ただし、この機能に渡される引数の型は になります。また、実行時エラーにつながる機能はありません。この種のエラーは、CAT コール (可用性またはタイプの変更) として知られています。a
B
A
A
qux
この問題の解決策は、共分散をポリモーフィズムと一緒に使用しないようにすることです。つまり、呼び出しはポリモーフィックであってはならず、引数の共変再宣言があってはなりません。このソリューションの作業は進行中です。