ようこそ。睡眠不足なプログラマのチラ裏です。

いまさら聞けないC#2.0の匿名メソッドとクロージャ (Closure)

Joe Walnes - The power of closures in C# 2.0
http://joe.truemesh.com/blog//000390.html

RubyC#2.0のクロージャが比較されている。
こうあらためて見ると、やはりRubyの構文は洗練されているなーという印象。


クロージャとは

クロージャとは関数の局所変数を 静的スコープに閉じ込めて、
その関数の外側から参照しアクセスできるようにするオブジェクトのことである。
もっと噛み砕いて言えば、関数の中に書ける静的スコープを持つブロック化されたコードのことである。
興味深いのは、クロージャが実際には局所的なコンテキスト(変数が存在するスタックフレーム)をパッケージし、
それらが実際に存在するスコープの外からも利用可能だという点。
つまり、クロージャは時としてオブジェクトのより良い代替となる。


C#2.0の匿名メソッドとクロージャ
さて、C#2.0にはインラインで書かれたメソッドをdelegate型に暗黙的に変換する
匿名メソッドとゆー機能があるが、その機能はクロージャの機能を有している。
ただし、C#2.0の匿名メソッドとゆーのは、あくまでメソッドであるので、必ず何らかのクラスに属している。
つまり、匿名メソッドとゆーのは実はコンパイラが生成する匿名クラスのインスタンスに属している。
C#.2.0でクロージャを記述するとき、匿名メソッドで使用している変数が、匿名メソッドと異なるスコープを持つ場合と、
匿名メソッドで使用している変数が、匿名メソッドと同じスコープを持つ場合の挙動が異なるのはこのためである。
であるから、C#2.0の匿名メソッドによって表現するクロージャというのは、
厳密なレキシカルクロージャとは少々異なる挙動をするという点では注意が必要だ。


クロージャの用途
クロージャの使い方もアイディアひとつで様々であるが、
その1つとして、クロージャを関数への引数として渡すことで、
利用者が関数の挙動をカスタマイズすることができるように設計することができる。
例えばソートを行う関数では、比較を評価するコードをクロージャとして引数にとることで、
利用者が自由に定義した条件でソートをすることができる。


また、クロージャは、遅延評価(呼び出されるまで実行されない)の性質を持つので、
制御構造の定義に用いることができる。つまり遅延評価では、値が必要になるまで実際の計算を行わない。
評価法が指示されているが実際の計算が行われていない中間状態であるプロミス (promise) 、
計算の実体をさすものをサンク (thunk) といい、プロミスを強制(force)することで値が計算される。
一旦計算された値をキャッシュすることにより、遅延プロミスは最大で一度しか計算されないようにすることができる。
必要なときだけ値を計算することで、計算量を低減できる。


ちなみにC#3.0では、クロージャをラムダ式(lambda)で書くことができる。