クラスはキーワード class の後にクラス名を付けて宣言する。
# class counter = object val mutable i = 0 method get = i method inc = i <- i + 1 method dec = i <- i - 1 end;; class counter : object val mutable i : int method dec : unit method get : int method inc : unit end #
モジュールと同様に複数の式を一つのまとまりとして扱うことが出来る。ただし、モジュールと違い、複数の値全体がひとつの値として扱われている。 また、val と method の区別がある。val はインスタンス毎に生成される値 (Counter.t 型の値に対応する)、method はインスタンスに共通の値(Counter モジュールに属する値に対応する)である。
counter クラスから counter オブジェクトをインスタンス化して使用するには、new キーワードを用いる。また、オブジェクトに # とメソッド名を付けて、メソッドを起動出来る。
# let c = new counter in c#inc; c#inc; c#get;; - : int = 2 #
クラスを定義せずに直接オブジェクトを作ることも可能。
# let c = object val mutable i = 0 method get = i method inc = i <- i + 100 end;; val c : < get : int; inc : unit > = <obj> # c#inc; c#inc; c#get;; - : int = 200 #
オブジェクトは値であり、関数の引数として利用できることが重要な点である。
クラスを継承したい場合、inhreit キーワードを用いる。
# class setable init = let restrict x = max 0 (min 100 x) in object (self) inherit counter method private set x = i <- x initializer self#set (restrict init) end;; class setable : int -> object val mutable i : int method dec : unit method get : int method inc : unit method private set : int -> unit end # let s = new setable 200 in s#get;; - : int = 100 #
上の例では inherit の他にクラス定義に便利な機能を(無理矢理)利用してみた。以下の特徴がある。
as キーワードにより、親クラスに名前を付けることも出来る。
# class resetable init = object inherit setable init as super method reset = super#set 0 end;; class resetable : int -> object val mutable i : int method dec : unit method get : int method inc : unit method reset : unit method private set : int -> unit end #
private 指定されたメソッドもサブクラスで利用できることに注意。多重継承も可能である。もし同名のメソッドがある場合は、最後の定義のみが有効になる。
クラスにおける parametric polymorphism の扱いには少し注意が必要である。クラスメソッドの型変数は、クラスもしくはメソッドに束縛されていなければならない。
# class id = object method id x = x end;; Some type variables are unbound in this type: class id : object method id : 'a -> 'a end The method id has type 'a -> 'a where 'a is unbound #
# class ['a] id = object method id (x : 'a) = x end;; class ['a] id : object method id : 'a -> 'a end # let s = new id;; val s : '_a id = <obj> # s#id "str";; - : string = "str" # s#id 1;; This expression has type int but is here used with type string #
# class id = object method id : 'a. 'a -> 'a = fun x -> x end;; class id : object method id : 'a -> 'a end # let i = new id;; val i : id = <obj> # i#id "str";; - : string = "str" # i#id 1;; - : int = 1 #
クラスが継承される事を前提にして、型だけ定義して実装を伴わないメソッドを宣言できる。
# class virtual printable = object (self) inherit counter as super method virtual print : unit method inc = self#print; super#inc end;; class virtual printable : object val mutable i : int method dec : unit method get : int method inc : unit method virtual print : unit end # new printable;; One cannot create instances of the virtual class printable #
printable クラスを継承して print メソッドを実装してみる。
# class cui_printable = object inherit printable method print = Format.printf "%d@," i end;; class cui_printable : object val mutable i : int method dec : unit method get : int method inc : unit method print : unit end # let cp = new cui_printable;; val cp : cui_printable = <obj> # cp#inc;; 0 - : unit = () # cp#inc;; 1 - : unit = () #
# let name x = x#name;; val name : < name : 'a; .. > -> 'a = <fun> #