GenericsとMacro

過去に散々やったネタですが、

using System.Console;

module Program {
  static Add ['t] (x : 't, y : 't) : 't {
    x + y;
  }
  static Main () : void {
    def x = 10;
    def y = 20;
    def a = "Hello, ";
    def b = "World.";

    WriteLine (Add (x, y));
    WriteLine (Add (a, b));
  }
}

上記の様にジェネリックなAdd関数を用意し、数値なら算術演算、文字列なら連結をさせたいとしても、型パラメータ'tは+オペレータをサポートしていないため、

n3.n:5:1: error: cannot find the operator `op_Addition' in neither 't.3 nor 't.3
n3.n:4:8: error: there were errors compiling method Program.Add(x : 't.3, y : 't.3) : 't.3

こんな風に怒られてしまいます。仕方ないと言えば仕方ないのですが、C++の様にコンパイル時に展開してくれると嬉しいケースもあったりします。Nemerleの場合、マクロをサポートしているので、マクロでごにょごにょすれば上手く行きそうな気がしたので実験です。

macro add (x, y) {
  <[ $x + $y ]>
}

こんなコードを打ち込んでadd.nとか名前を付けて保存します。で、マクロをコンパイル

$ ncc -t:library -r:Nemerle.Macros.dll -o:add.dll add.n

addマクロのアセンブリが出来ました。こいつを使ってみます。

using System.Console;

module Program {
  static Main () : void {
    def x = 10;
    def y = 20;
    def a = "Hello, ";
    def b = "World.";

    WriteLine (add (x, y));
    WriteLine (add (a, b));
  }
}

上記のようなサンプルをこさえて、先ほどのマクロアセンブリを参照に加えてコンパイル

$ ncc -r:add.dll -o:sample.exe sample.n

で、実行すると

30
Hello, World.

期待通りの結果になりました。こいつを逆コンパイルしてみると、

private static void Main()
{
      int num1 = 10;
      int num2 = 20;
      string text1 = "Hello, ";
      string text2 = "World.";
      Console.WriteLine( (int) (num1 + num2));
      Console.WriteLine(text1 + text2);
}

addマクロが展開されているのが分かります。マクロとジェネリックスを使い分ければ色々面白いことが出来そうですね。