C#2.0のanonymous methodはclosureか?

少し古くなるのだが、Martin Fowler's BlikiにClosuresという記事があった(日本語版はここ)。この記事では、rubyを例にclosureとC#delegateJavaのanonymous class、Cの関数ポインタとの違いが述べられていた。

closureって何ですか?という人もいると思うのでBlikiの中での定義を以下にまとめると次のようになる。

  1. closureは、引数を受け取ることができるコードブロック*1のこと
  2. closureは自身が定義されている環境を参照することが可能

1について、Blikiの例を見ながら説明する。

def managers(emps)
	return emps.select {|e| e.isManager}
end

selectの右側にあるコードブロックがclosureである。このclosureはempsの要素(Employee)を引数として受け取り、受け取ったEmployeeがManagerかどうかの真偽値を返す。
selectは、自身が保持するすべての要素に対し引数として渡されたclosureを評価し、その返り値が真である要素のリストを返す関数である。

次に、2について説明する。

def highPaid(emps)
	threshold = 150
	return emps.select {|e| e.salary > threshold}
end

この例では、selectに渡されるclosureの中で外の環境の変数thresholdを参照している点に注目して欲しい。このような参照は、関数ポインタやdelegateではできない。

ここまでの例を見てclosureってC#2.0のanonymos methodなのでは?と思った人も多いと思う。実際、私もそう思った一人である。この認識はほぼ間違いないと思うのだが、念のためVS2005を使ってBlikiにあるコードを記述できることを確認してみた。

確認に用いたコードは以下のものである。

public static List Managers(List emps)
{
    return emps.FindAll(delegate(Employee e)
    {
       return e.IsManager;
    }
    );
}

public static List HighPaid(List emps)
{
    int threshold = 150;
    return emps.FindAll(delegate(Employee e)
    {
       return threshold < e.salary;
    }
    );
}

やはり、closure = anonymous methodという認識は間違っていないと思われる。ちなみに、

def paidMore(amount)
	return Proc.new {|e| e.salary > amount}
end

Blikiのこの例は、C#2.0では次のように書ける。

public static Predicate PaidMore(int amount)
{
    return delegate(Employee e)
    {
        return e.salary > amount;
    };
}

最後に、

The second difference is less of a defined formal difference, but is just as important, if not more so in practice. Languages that support closures allow you to define them with very little syntax. While this might not seem an important point, I believe it's crucial

Martin Folwer氏曰くclosureは文法的に簡単に記述できることが重要らしい。この点について、C#2.0のanonymous methodはなんとか及第点は取れたという感じなのではないかと思う。(Rubyのclosureと比べたら文法が複雑だと思うので。)

*1:これって、λ式のことなんじゃないかと思った。selectに渡されるブロックだと、λe. e.isManagerと書けるのでしょう。たぶんですが。