読者です 読者をやめる 読者になる 読者になる

型推論,IntelliSense,Extension Methods

.NET

こんなメソッド呼出しがあるとします.なお大文字はメソッドで,小文字は変数です.

A( B( C(a), b, D( E(c), d, e ) ) );

メソッド A, B, C, D, E はいくつかのオーバーロードを持つことがありますが,呼出しが (C++ なり C# 2.0 なりの推論規則で) 曖昧でなければコンパイルは通ります.またメソッド A, B, C, D, E が (C++ で言うところの) template メソッドまたは (C# 2.0 で言うところの) generic メソッドであるとき,型パラメータを明示しなくても (C++ なり C# 2.0 なりの推論規則で) 曖昧でなければやはりコンパイルは通ります.
経験上 C++ なり C# 2.0 なりのこのような推論は,呼出しの枝の末端から根に向かう方向に行われているように見えます.

  • A
    • B
      • C
        • a
      • b
      • D
        • E
          • c
        • d
        • e

つまり,このようなツリーに対して「(E決定→D決定,C決定)→B決定→A決定」という順序で最終的なメソッドが決まるようです.
これはこれで結構なことですが,IntelliSense を前提に「左から」入力していくというシナリオでは若干の相性の悪さが見られます.つまり,一番最初に入力するはずのメソッド A の決定が遅延させられているため,IntelliSense にとっても「名前が A であるメソッド」ということ以上のことが分からないという状況が発生しています.
一方,C# 3.0 の Extension Methods を使えば,上の式は次のように書き換えることが出来る可能性があります.

a.C().B(b, c.E().D(d, e)).A();

まだメソッド B,D にオーバーロード・型パラメータについて曖昧性が発生する可能性は残っていますが,「左から」入力していく上で明らかに IntelliSense が活用できる情報が増えているように見えます.
LINQ 発表時に Visual Basic 9 (の query operator) では SQL のように先頭に select を書ける一方で,C# 3.0 では後置的に select を記述することについて「SQL 的ではないけどいいの?」という疑問が散見されましたが,このような視点で見直すとなるほど select が最後に来ることのメリットは大きいように見えてきますね.
なお,select の位置に関する詳しい背景事情は次の資料にまとまっています.