What is it, naokirin?

OCamlのクラス

今日はTDD Boot Camp 福岡にてOCamlを使うことになってますが、昨日OCamlの本のGUIライブラリの部分以外を読み終えたばかりというところです。
しかもクラスや多相ヴァリアントなどはほとんど打ち込んでもいないので、かなり他の人の足を引っ張るのではないかと心配です。

ということで、少しだけクラスを使ってみました。またもやFizzBuzzを題材に。(我ながら芸が無いです…)

テストコード

open Fizzbuzz;;
open OUnit;;

let testFizzBuzz =
  (List.map
    (fun (arg,res) ->
      let fb = new fizzbuzz in
      let actual = fb#set_num arg; fb#says
      in
        let test =
          Printf.sprintf "actual:%s -> expected:%s" actual res
        in
        test >::
          (fun () ->
            assert_equal res actual
          )
    )
    [1, "1"; 3, "Fizz."; 5, "Buzz."; 15, "FizzBuzz."]
  );;

let suiteFizzBuzz =
  "suiteFizzBuzz">::: testFizzBuzz

let _ =
  run_test_tt_main suiteFizzBuzz
class fizzbuzz =
   object
     val mutable num = 1
     method says = if (num mod 15) = 0 then "FizzBuzz."
                   else if (num mod 3) = 0 then "Fizz."
                     else if ( num mod 5) = 0 then "Buzz."
                       else Printf.sprintf "%d" num
     method set_num = fun x -> num <- x
  end;;

かなり基本的なクラスの使い方ですね。
実際に上のクラスを使う際には

# let fb = new fizzbuzz;;
val fb : fizzbuzz = <obj>
# fb#says;;
- : string = "1"
# fb#set_num 3; fb#says;;
- : string = "Fizz."

のようになります。new 〜でクラスのインスタンスの生成、# でメソッド呼び出しを行います。

また継承を使う場合はinheritで宣言し

class fizzbuzz_second =
  object
    inherit fizzbuzz
    method next = num <- num + 1
  end;;

のようにします。この場合はfizzbuzzにnextというメソッドを追加したfizzbuzz_secondクラスを作っています。また継承元(親クラス)にあるメソッドと同じ名前のメソッドを定義することでメソッドを再定義できます。

クラスには自分をさす変数と親クラスをさす変数を定義できます。これを使うとクラス内で自分や親クラスのメソッドを呼び出すことができます。

class fizzbuzz_second =
  object (self)
    inherit fizzbuzz as super
    ...
  end;;

この場合は自分自身はself、親クラスfizzbuzzはsuperという変数になっています。

また初期化のためにオブジェクト生成時に引数をもらうことや、初期化時に呼び出される処理を書くための構文が用意されています。

class fizzbuzz_third x=
  object (self)
    inherit fizzbuzz
    initializer self#set_num x ;Printf.printf "%s" self#says
  end;;

クラス名の後ろにオブジェクト生成時に渡す引数を書いています。またintializer 〜でオブジェクト生成時の初期化を行っています。今回の場合は受け取った引数をset_numに渡して、その後saysを呼び出して表示するようにしています。
initializerの後ろに来る式はunit型でなければなりません。

またメソッドをprivateにすることもできます。

class fizzbuzz_fourth =
  object (self)
    inherit fizzbuzz
    method private next = num <- num + 1
    method says = self#next;
                  if (num mod 15) = 0 then "FizzBuzz."
                  else if (num mod 3) = 0 then "Fizz."
                    else if ( num mod 5) = 0 then "Buzz."
                      else Printf.sprintf "%d" num 
  end;;

これにより外部からはnextを呼び出すことができなくなりました。

最初のコード以外にテストコードが付いていないのは御愛嬌ということにしてください。
さてさて、急がないとTDD Boot Campに遅刻しますのでこのあたりで終わりということにします。