オブジェクトのメソッドとか

すごい基本的な内容だけど、こういうのさえマニュアルには無いので困る。オブジェクト関連はOcamlとF#で違うみたいなので、Ocamlもあまり参考にならない。
C#をやってたりするとこういうところで勘が働くのかなあ。
というわけでオブジェクトのコード。

// F#のバージョン: 1.9.2.9
////////////// オブジェクト

type TestBase = class 
    new () = {}  
    // abstract でオーバーライド可能なメソッドを宣言
    abstract Test0 : unit -> string
    abstract Test3 : unit -> string

    // abstract は default か override でオーバーライドする。
    // 両者は異なるバイナリを生成するが、処理的には変わりは無いようだ。
    default  x.Test0() = "TestBase Test0 abstract"
    member   x.Test1() = "TestBase Test1"
    member   x.Test2() = x.Test0()
    default  x.Test3() = x.Test2()
    member   x.Test4() = x.Test3()

     override x.Finalize() = printf "Finalize() of %s called!!!\n" (x.ToString())
end

let scope_test = fun () -> 
    let temp_object = new TestBase() in 
    printf "temp_object is created\n";
    // ここでGCを呼んでもFinalize()は呼ばれない。
    System.GC.Collect();
    // ここにprintfを入れないと、上のGCが間に合って回収されちゃうことも
    printf "Finalize() has not been called yet.\n";;

do scope_test()

// Finalize() はスコープ外にでた瞬間には呼ばれない。
do printf "Finalize() has not been called yet.\n"

// ここでGCさせるとFinalize()が呼ばれる。
do System.GC.Collect()


let testbase = new TestBase()
// default で宣言した関数を呼ぶ。
// 引数部分はこの場合カッコで囲まないとコンパイルエラー。
do printf "abstract TestBase.Test0() = '%s'\n" (testbase.Test0())
// abstract と member の混在
do printf "member   TestBase.Test4() = '%s'\n" (testbase.Test4())


// abstract なオブジェクトはコンストラクト時にオーバーライド可能
// member は不可。また、フィールドも不可(mutable でも不可)。
// フィールドの初期化はclassのコンストラクタ内で行うべし。
let testbase2 = {new TestBase() with Test0() = "TestBase Test0 overrided when construction"}
do printf "member   TestBase.Test4() = '%s'\n" (testbase2.Test4())



////////////// 継承やらオーバーライドやら

type TestSub = class
    inherit TestBase as base
    new() = { }
    // メソッドをオーバーライド。
    override x.Test0() = "TestSub Test0"
    // Test2 を上書き。
    member   x.Test2() = x.Test1()
end

let testsub = new TestSub()

// オーバーライドしたメソッドを呼ぶ
do printf "abstract TestSub.Test0()               = '%s'\n" (testsub.Test0())
// abstract の関数をTestBaseにキャストして呼んでも同じ
do printf "abstract (TestSub :> TestBase).Test0() = '%s'\n" ( (testsub :> TestBase).Test0())

// 通常(abstract でない)の上書きしたメソッドを呼ぶ
do printf "member   TestSub.Test2               = '%s'\n" (testsub.Test2())
// 通常の上書きしたメソッドをTestBaseにキャストして呼ぶと、
// TestBaseのメソッドが呼ばれる。(その結果、上書きしたTest0が呼ばれる)
do printf "member   (TestSub :> TestBase).Test2 = '%s'\n" ( (testsub :> TestBase).Test2())

// Test3スロットにはTestBase.Test2が入っているので、
// TestBaseにキャストした場合のTest2と同じ結果になる
do printf "abstract TestSub.Test3               = '%s'\n" (testsub.Test3())


////////////// さらに継承

type TestSubSub = class
    inherit TestSub as base
    new() = { }
    override x.Test0() = "TestSubSub Test0"
    override x.Test3() = x.Test2()
end

let testsubsub = new TestSubSub()

// Test3のスロットにTestSubSub1のものが入っているので、キャストしても同じ
do printf "member   TestSubSub.Test4               = '%s'\n" (testsubsub.Test4())
do printf "member   (TestSubSub :> TestSub).Test4  = '%s'\n" ( (testsubsub :> TestSub).Test4())
do printf "member   (TestSubSub :> TestBase).Test4 = '%s'\n" ( (testsubsub :> TestSub).Test4())

はてなの記法でocamlを指定してみたけどF#はかえってみにくいのでやめ。