3.17 Friend

上記の money クラスは、バイナリメソッドとともによく生じる問題を示しています。同じクラスの他のオブジェクトとやりとりするために、 money オブジェクトの内部表現を value のようなメソッドを通じて公開しなくてはいけません。もしすべてのバイナリメソッド (ここでは plusleq) を取り除けば、内部表現は 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 節「集合 」にもあります。これらの例は、複数のオブジェクト(ここでは同じクラスに属するオブジェクト)と関数が互いに相手の内部表現を知る必要があるのに、その外側からは内部表現が隠されている必要があるときに生じます。この問題を解決するには、すべてのフレンドをかならず同じモジュールで定義して内部表現を得る方法を与え、かつシグネチャでその表現を捨象する制約を与えモジュールの外には隠蔽します。