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が呼び出されるわけですね.
まぁ,なんとなく予想通りだったので特に言うことはないのですけど,この辺を他人に説明するのは気が重いかなぁ?目を白黒させてしまいそうです(^^;;
今日はここまで