Nemerle for OOP Programmers Week 1 (5)

Static constructors

本当はこの前にExamplesがあるのですが,とりあえずパス.
Staticコンストラクタは,プログラム(AppDomain)単位でただ1回だけ呼び出される,staticフィールドを初期化するために用意されたコンストラクタです.ちなみに呼び出されるのはクラスが最初に参照されたときなので,

using System.Console;
 
class Hello {
  static this ()
  {
    WriteLine ("static ctor");
  }
 
  static public Run () : void
  {
    WriteLine ("Run");
  }
}
 
WriteLine ("hello");
Hello.Run ();
WriteLine ("bye");
 
/* Output:
hello
static ctor
Run
bye
*/

となります.

Properties

プロパティもC#と同じっぽい.

using System.Console;
 
class MyClass {
  mutable m_foo : int;
  
  public Foo : int
  {
    get { 
      WriteLine ("get_Foo called");
      m_foo
    }
    set {
      when (value > 3)
        WriteLine ("value bigger than three");
      m_foo = value;
    }
  }
}
 
def c = MyClass ();
c.Foo = 1;
WriteLine ($ "c.Foo = $(c.Foo)");
c.Foo += 42;
WriteLine ($ "c.Foo = $(c.Foo)");
 
/* Output:
get_Foo called
c.Foo = 1
get_Foo called
value bigger than three
get_Foo called
c.Foo = 43
*/

getプロパティにはついreturnを書きたくなります(^^;;
それを除けば特に引っかかるところもありません.
むしろ,

WriteLine ($ "c.Foo = $(c.Foo)");

これは

WriteLine ("c.Foo = {0}", c.Foo);

と同じ意味です.Bash(というかBourne sh)を生業としていた時期もあったので,どちらでも違和感はありません.

The [Accessor] macro

単にgetterのみのプロパティを作りたいなら,[Accessor]マクロが使えるようです.

using Nemerle.Utility;
 
class MyClass {
  [Accessor]
  foo_bar : string = "qux";
}
 
def c = MyClass ();
System.Console.WriteLine (c.FooBar);
 
/* Output: qux */

FooBarなんてどこにも定義してないんですが,foo_barからアンダースコアを取って単語の先頭を大文字にする,みたいな変換規則があるんでしょうね.
ちなみに詳細はWikiのほうに書かれているらしいのですが,何故か現在工事中(?)で見れません.残念

Inheritance and virtual calls

継承もC#と同じ.またvirtual/overrideの概念も同じのようです.
さて,このへんでちょっと実験してみましょう(写経ばかりじゃ飽きますもんね).

using System.Console;

class Robot {
  public virtual SelfDestruct () : void
  {
    // call robot firmware here
    WriteLine ("...")
  }
}
 
class R2D2 : Robot {
  public override SelfDestruct () : void
  { 
    WriteLine ("refusing");
  }
}
 
class Marvin : Robot {
 // don't override anything
}

def robot : Robot = R2D2 ();
robot.SelfDestruct();
WriteLine("");
def marvin : Robot = Marvin ();
marvin.SelfDestruct();

/* Output:
refusing

...
*/

R2D2は正しくOverrideされ,Marvinは何もOverrideしていないのでRobotのSelfDestructが呼び出されてます.
それでは,

using System.Console;

class Robot {
  public virtual SelfDestruct () : void
  {
    // call robot firmware here
    WriteLine ("...")
  }
}
 
class R2D2 : Robot {
  public new SelfDestruct () : void
  { 
    WriteLine ("refusing");
  }
}
 
class Marvin : Robot {
 // don't override anything
}

def robot : Robot = R2D2 ();
robot.SelfDestruct();
WriteLine("");
def marvin : Robot = Marvin ();
marvin.SelfDestruct();

/* Output:
...

...
*/

R2D2のSelfDestructにoverrideキーワードを使わないとポリモーフィズムになりません.
最後に

using System.Console;

class Robot {
  public virtual SelfDestruct () : void
  {
    // call robot firmware here
    WriteLine ("...")
  }
}
 
class R2D2 : Robot {
  public new SelfDestruct () : void
  { 
    WriteLine ("refusing");
  }
}
 
class Marvin : Robot {
 // don't override anything
}

def robot = R2D2 ();
robot.SelfDestruct();
WriteLine("");
def marvin = Marvin ();
marvin.SelfDestruct();

/* Output:
refusing

...
*/

このケースではrobotの型を明示せず,型推論に頼っています.するとrobotは(多分)R2D2型に推論されるので,R2D2のSelfDestructが呼び出されるわけですね.


まぁ,なんとなく予想通りだったので特に言うことはないのですけど,この辺を他人に説明するのは気が重いかなぁ?目を白黒させてしまいそうです(^^;;


今日はここまで