最初の例をまず取り上げます。OCaml には、名目上の型付けではなく、オブジェクトの構造的な型付けがあります。つまり、オブジェクトの型は、そのメソッド (およびその型) によって完全に決定されます。したがって、クラスa
とb
は実際には同じ型です。
$ ocaml
OCaml version 4.00.0
# class a = object method get (x: a) = x end;;
class a : object method get : a -> a end
# class b = object inherit a method get (x: b) = x end;;
class b : object method get : a -> a end
# let a0 = new a;;
val a0 : a = <obj>
# let b0 = new b;;
val b0 : b = <obj>
# (a0: b);;
- : b = <obj>
# (a0: a);;
- : a = <obj>
# (b0: a);;
- : a = <obj>
# (b0: b);;
- : b = <obj>
#
(ここで示そうとしているのは、a0
andの両方b0
が typea
とtypeであることb
です。)
get
2 番目の例では、メソッドに新しい型を与えようとしていると言えます。OCaml でメソッドをオーバーライドする場合、パラメーターと戻り値の型は親クラスと同じである必要があります。
エラーメッセージは残念です。私の推測では、コンパイラは type が typeb
の別の名前であるとあなたを信じていますa
。
OCaml の強みの 1 つは、型を推論することです。in class: b
のパラメータの for を省略すると、代わりに次のエラーが発生します。get
b
This expression has type a. It has no method foo
a
これは、パラメーターの型が必要であることを示している (私が思うに) という点で、もう少し役に立ちます。
余談 (すみません): 主流の OO 言語から OCaml の OO 部分にたどり着いた場合、奇妙に感じるかもしれません。しかし、最初に OCaml の FP 部分を学ぶと、なぜすべての主流の OO 言語がこれほど多くの間違いを犯すのか不思議に思うかもしれません :-)。(確かに、すべてはトレードオフであり、計算を構造化する唯一の正しい方法はありません。しかし、OCaml の OO サブシステムはかなり印象的なことを行っています。)