3.3 自分自身への参照

メソッドや初期化子は自分自身、つまり現在のオブジェクトのメソッドを呼び出すことができます。このためには、ここで変数 s になされているように、自分自身を明示的にある変数に束縛する必要があります(s はどんな識別子でも構いませんが、 self という名前がよく使われます)。

#class printable_point x_init =
   object (s)
     val mutable x = x_init
     method get_x = x
     method move d = x <- x + d
     method print = print_int s#get_x
   end;;
class printable_point :
  int ->
  object
    val mutable x : int
    method get_x : int
    method move : int -> unit
    method print : unit
  end

#let p = new printable_point 7;;
val p : printable_point = <obj>

#p#print;;
7- : unit = ()
    

変数 s はメソッドの起動時に動的に束縛されます。 特にクラス printable_point が継承された場合、 s はその子クラスのオブジェクトに束縛されます。

self に関するよくある問題は、それが子クラスで拡張可能であるという問題点です。これは避けることができません。簡単な例は以下のようになります。

#let ints = ref [];;
val ints : '_a list ref = {contents = []}

#class my_int =
   object (self)
     method n = 1
     method register = ints := self :: !ints
   end;;
This expression has type < n : int; register : 'a; .. >
but is here used with type 'b
Self type cannot escape its class
    

最初の2つのエラーは無視することができます。問題は最後のエラーで、 self を外部の参照に置くと、あとでそれが拡張できなくなるという点です。これについては、 3.12 節「型変換の使用」で詳しく説明します。さしあたっては、直接生成されたオブジェクトは拡張ができないので、この問題は起こらないということを覚えておいてください。

#let my_int =
   object (self)
     method n = 1
     method register = ints := self :: !ints
   end;;
val my_int : < n : int; register : unit > = <obj>