この IBM の論文は、BGGA と CICE の構文の違いの良い例を示しています。
BGGAの提案
BGGA 提案は、型付き引数リスト、戻り型、および throws 節を持つ関数型の概念を作成します。BGGA 提案では、平方和コードはリスト 9 のコードのようになります。
リスト 9 . BGGA クロージャー構文を使用した二乗和の計算
sumOfSquares = mapReduce(myBigCollection,
{ Double x => x * x },
{ Double x, Double y => x + y });
=> 記号の左側にある中括弧内のコードは、引数の名前と型を識別します。右側のコードは、定義されている無名関数の実装を表しています。このコードは、ブロック内で定義されたローカル変数、クロージャへの引数、またはクロージャが作成されたスコープからの変数を参照できます。
BGGA 提案では、関数型である変数、メソッド引数、およびメソッドの戻り値を宣言できます。単一の抽象メソッド クラス (Runnable や Callable など) のインスタンスが期待される任意のコンテキストでクロージャを提供できます。匿名で型指定されたクロージャーの場合、invoke() メソッドが提供されているため、指定された引数リストを使用してそれらを呼び出すことができます。
BGGA 提案の主な目標の 1 つは、プログラマーが制御構造のように機能するメソッドを作成できるようにすることです。それに応じて、BGGA は、クロージャーを受け入れるメソッドをあたかも新しいキーワードであるかのように呼び出せるようにする構文糖衣も提案しています。リスト 10 は、BGGA 提案の下で withLock() メソッドがどのように定義されるかを示しています。リスト 11 とリスト 12 は、標準形式と「制御構成」形式の両方を使用して、どのように呼び出されるかを示しています。
リスト 10 . BGGA クロージャ提案の下での withLock() メソッドのコーディング
public static <T,throws E extends Exception>
T withLock(Lock lock, {=>T throws E} block) throws E {
lock.lock();
try {
return block.invoke();
} finally {
lock.unlock();
}
}
リスト 10 の withLock() メソッドは、ロックとクロージャーを受け入れます。クロージャーの戻り値の型と throws 句は、一般的な引数です。コンパイラーの型推論では、通常、T と E の値を指定せずに呼び出すことができます (リスト 11 とリスト 12 を参照)。
リスト 11 . withLock() の呼び出し
withLock(lock, {=>
System.out.println("hello");
});
リスト 12 . コントロール コンストラクトの短縮形を使用して withLock() を呼び出す
withLock(lock) {
System.out.println("hello");
}
ジェネリックと同様に、BGGA 提案の下でのクロージャの複雑さの多くは、ライブラリの作成者が負担しています。クロージャーを受け入れるライブラリ メソッドを使用する方がはるかに簡単です。
BGGA の提案は、内部クラスのインスタンスを使用してクロージャーの利点を得ようとするときに存在する多くの透過性の障害を修復するためにも機能します。たとえば、return、break、および this のセマンティクスは、同じコード ブロックを表す Runnable (または他の内部クラス インスタンス) とコード ブロックでは異なります。これらの非透過性の要素は、汎用アルゴリズムを利用するためにコードを移行する際に混乱を招く可能性があります。
CICEの提案
CICE 提案は、内部クラス インスタンスのインスタンス化が面倒すぎるという問題に対処する、より単純な提案です。関数型の概念を作成するのではなく、単一の抽象メソッド (Runnable、Callable、または Comparator など) を使用して内部クラスのインスタンスをインスタンス化するためのよりコンパクトな構文を作成するだけです。
リスト 13 は、CICE の下で平方和コードがどのようになるかを示しています。mapReduce() で使用される UnaryFunction および BinaryFunction 型を明示的にします。mapReduce() の引数は、UnaryFunction および BinaryFunction から派生した無名クラスです。この構文は、匿名インスタンスの作成に関連する冗長性の多くを排除するだけです。
リスト 13 . CICE閉鎖提案の下での二乗和コード
Double sumOfSquares = mapReduce(myBigCollection,
UnaryFunction<Double>(Double x) { return x*x; },
BinaryFunction<Double, Double>(Double x, Double y) { return x+y; });
mapReduce() に渡される関数を表すオブジェクトは通常の匿名クラス インスタンスであるため、それらの本体は外側のスコープで定義された変数を参照できます。リスト 13 とリスト 7 のアプローチの唯一の違いは、構文が冗長であることです。