top down vs. bottom up (1)
- http://blogs.wankuma.com/mnow/archive/2008/01/24/118970.aspx:title=
- http://blogs.wankuma.com/mnow/archive/2008/01/24/119056.aspx:title=
- http://blogs.wankuma.com/mnow/archive/2008/01/25/119216.aspx:title=
- http://blogs.wankuma.com/mnow/archive/2008/01/25/119319.aspx:title=
うーむ,色々書きたいけど確かに 4 回シリーズぐらいになりそう.
2005 年当時,私が「LINQ すげー」と思ったのは,こちらの反応が読まれているかのように数手先まで用意されていたところですかね.
ただの IEnumerable<T> 連鎖は,アルゴリズム的な最適化という面で確かに完璧ではありません.が,それに対する回答すら最初の発表で用意されていました.しかもその実例として SQL への実行時変換という破壊力抜群 *1 を持ってこられると,できすぎとしか言いようがありません*2.
つまり,
個人的な予想では,System.Query 以下の汎用 Standard Query Operators は多くの C++ STL Algorithm のようにな代物にとどまるのではないかと思います.単にアルゴリズムが教科書通り実装されているだけと(追記: C:\Program Files\LINQ Preview\Docs\Sequence.cs に実装がソースコードの形で公開されています).ただし .NET の inlining はまだまだ甘いところがあるので,今のところ速度面ではそこまで期待していません.
というネタだけでリリースすれば,今回えムナウさんが書かれているようなパフォーマンス上の問題提起や反論だってみんなするでしょう.その不安に対して,「じゃあこうしたらどうでしょう?」という回答までちゃんと付いていたことが驚きなわけです.
さてここからはおまちかねの応用編.
通常の Standard Query Operators では末端の IEnumerable<T> の条件を上流の IEnumerable<T> にうまく伝える方法がありません.下の例を見てください.
public static IEnumerable<T> OfType<T>(this IEnumerable source) { foreach (object item in source) if (item is T) yield return (T)item; }このコードでは,型 T でフィルタリングするという情報が上流の source に伝わらないため,無駄な列挙が行われる可能性があります.これがデータベースに対するクエリであれば,そもそも必要なかった要素まで受け取り,あとでそれを捨てるという羽目になりかねません.
DLinq は Standard Query Operators をオーバーロードすることでこの問題を回避しています.
そもそも C# 2.0 すら RTM を迎えていないあの時期に,C# 2.0 流のコレクションライブラリの発展系 (Linq to Object) がどうなって,さらにその限界を打ち破るには何が必要かまで読み切っていたところにぐっときたと.
そういった将来の可能性が見えていればこそ安心できるというのもあります.私が現在 Linq to Object を教材に C# のプログラミングスタイルを色々試行錯誤しているのも,将来的な伸びしろを考えると,LINQ のセマンティクス/シンタックスでコードを残すことに価値があると信じているからですかね.
今のところ,式木レベルでの言語言語変換を行うには,「文」である for/foreach ではダメで,「式」である LINQ で処理を記述しなきゃならんわけですし*3.
次回は,実際に「式」の力で foreach 4 回の式を foreach 1 回の式に実行時変換する方法について見ていきたいと思います.
*1:主にマーケティング上の
*2:というのが外部視点.後で伝え聞いた話や『The Origin of LINQ to SQL』を総合すると,WinFS や Windows Vista といった要素も決して無関係ではなかったことも分かります