C#2.0時代のゲームプログラミング(30)


■ 何故このようなdelegateの実装になっているのか?


わざわざこんな複雑な実装にするメリットがどこにあるのだろう?


Visual Studio 2005の開発に従事しているAbhinaba氏のblogにはC#の匿名メソッドはclosureではないという記事があるが、この記事のその後の議論では「匿名メソッドはまさにlexical closureである」という結論に落ち着いている。


Fortran(すまん。不勉強なのでFortran77時代しか知らない。)のように関数の呼び出しのときのパラメータが参照で渡されたところで、必要なら関数本体の先頭でローカル変数にコピーしてそちらを使えばいい話だし、同様に、delegateがこのような実装になっていようが、必要なら匿名delegateの直前で別の変数にコピーして、その変数をdelegateのなかで参照すれば良い。この意味において、closure的に使うことが出来ると言える。


だからこのような実装になっていることによって、delegate内で同一の値型変数のインスタンスを参照するようなことが可能になる。具体的なメリットはそういうことだろう。


C#では値型変数を直接heapに確保できない。int i = new int();などとやったところで、それはstack上に確保される。boxingでは、boxingされたものをunboxingすることは出来ても直接その値を書き換えることが出来ない。値型変数をdelegateのなかから共有するには、結局 class IntObject { public int value; } のようなclassを用意して、こいつを使って共有するしかない。こうなるとアクセスするのに、intObject.Value = 3;などと書かなくてはいけなくなる。これは非常に冗長である。


すなわち、C#delegateが嫌らしいのではなく、C#に値型とオブジェクト型のような二つの仕組みの異なるdata typeがあるから嫌らしいのである。私は、値型をheap上に確保する構文があれば良いと思う。例えば、int^ i;のように宣言すればheap上に確保されるだとか。こういう機構があれば、delegateは現状のC#のような仕様になっていなくても済む。だけど、そういう構文がない限りは、delegateは、現状のC#のような仕様であるほうが好ましいと思う。ただ、誰もが一度は「アレ?」と思うだろうけれども。