コレクションと副作用

 LINQの登場により、C#ではコレクションを書き換える場合、列挙すると書き換えた結果をその場で作るIEnumerableを返すのが標準になったと理解している。それは元のコレクションを書き換えない、副作用の無い処理だ。

 IEnumerableといっても実際にコレクションを作るわけじゃなく、一つ一つの値をその場で作って返すだけなので、パフォーマンスもそう悪くない。これによりコレクションのインターフェースにはAddもInsertもRemoveも、書き変える物は何もかもいらなくなったと思う。一般的なアルゴリズムLINQで書き、特化された文脈ではコレクションの具体クラスをそのまま使えばいい。なので一般的なコレクションを所有したい場合、選択すべきクラスはSystem.Collections.ObjectModelのReadOnlyCollection(or その継承クラス)だと俺は思う。

 new List<int>{ 1, 2, 3 }; こんな風に書くとnewした後にAddが呼ばれるのだが、ICollectionのAddが呼ばれているわけじゃなく、Addという名前のメソッドを探して呼んでいるだけなのでやっぱりインターフェースにAddはいらない。だから.NET Frameworkのコレクションのインターフェース設計は、何もかも失敗だった。IEnumeratorにも、使ってはいけないResetなんてメソッドもある。

 使ってはいけないメソッド、実装してもあまり意味の無いinterface、そんなのばっかなのだが、たいして困ってない。もともとただの配列がIListを実装していて、AddやRemoveを呼ぶと例外が投げられるという実装がされていて、「interfaceとは、実装しないことと見つけたり」というような哲学を感じさせる設計になっている。「呼ぶと例外になるインターフェースメソッドがあってもいいんだ!」「一般化のために具体クラスを作ったら即interfaceの型の変数に入れましょう、なんてのはオブジェクト指向を思想と勘違いしたキチガイのたわごとなんだ!」というエヴァンゲリオン最終回のような悟り体験を得られる。これが正しいことは.NET Frameworkを実際に使えば分かる。

 つまりもともとオブジェクト指向とかinterfaceみたいなものは破綻している。破綻の芽を内包している物はいずれ必ず破綻する。結局usingでDisposeを呼び出せるようにするにも、IDisposableを使うのでなく、インターフェースメソッドにはクロージャを使い、記述の合理化にはコンセプトマップみたいなものを使って呼び出すメソッドを静的に指定すればよかったのだと思う。

 オブジェクトには状態を囲い込んで制御するという大事な役割がある。メソッドの抽象化はクロージャの仕事だ。