メソッドや初期化子は自分自身、つまり現在のオブジェクトのメソッドを呼び出すことができます。このためには、ここで変数 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>