上記の money
クラスは、バイナリメソッドとともによく生じる問題を示しています。同じクラスの他のオブジェクトとやりとりするために、 money
オブジェクトの内部表現を value
のようなメソッドを通じて公開しなくてはいけません。もしすべてのバイナリメソッド (ここでは plus
と leq
) を取り除けば、内部表現は value
を取り除くことで隠蔽することができます。しかし、このことは同じクラスに属する、自身とは異なるオブジェクトの内部表現を利用するバイナリメソッドがある限り不可能です。
#
class safe_money x = object (self : 'a) val repr = x method print = print_float repr method times k = {< repr = k *. x >} end;;
class safe_money : float -> object ('a) val repr : float method print : unit method times : float -> 'a end
ここでは、オブジェクトの内部表現は個々のオブジェクトのみに知られています。内部表現を同じクラスの他のオブジェクトに公開しようとすると、これを全世界に公開することを強いられてしまうのです。しかし、内部表現の可視性はモジュールによって簡単に制限できます。
#
module type MONEY = sig type t class c : float -> object ('a) val repr : t method value : t method print : unit method times : float -> 'a method leq : 'a -> bool method plus : 'a -> 'a end end;;
#
module Euro : MONEY = struct type t = float class c x = object (self : 'a) val repr = x method value = repr method print = print_float repr method times k = {< repr = k *. x >} method leq (p : 'a) = repr <= p value method plus (p : 'a) = {< repr = x +. p value >} end end;;
フレンドの他の例は 5.2.4 節「集合 」にもあります。これらの例は、複数のオブジェクト(ここでは同じクラスに属するオブジェクト)と関数が互いに相手の内部表現を知る必要があるのに、その外側からは内部表現が隠されている必要があるときに生じます。この問題を解決するには、すべてのフレンドをかならず同じモジュールで定義して内部表現を得る方法を与え、かつシグネチャでその表現を捨象する制約を与えモジュールの外には隠蔽します。