Java : インターフェースをnewする?
[id:lethevert:20060207:p1]の続き。
まず、Listは明らかに例が悪い
Listに限らず、コレクション系は、実装によってその性能特性がものすごく変わる。だから、もしもまじめに計算量のことを考えているプログラマなら、どんな場合でもそのListの実装がどうでもいいなんてことにはならないと思う。(ある実装なら数秒の処理が、ある実装だと数時間ということが、珍しくないのがデータ構造の世界だから)
しかし、それでも、
ArrayList list = new ArrayList();
と書かずに
List list = new ArrayList();
と書くかと言うと、プロトタイピングをしている時に、そのコードの負荷特性を見極められない or 見極めたと思っても後で状況が変わるかもしれないので、後から実装を差し替えたときに、コード全体にその影響を及ぼさないようにするための、初歩的な抽象化のため慣習があるからだ。
だから、ランダムアクセスの性能を求めるケースであることがあらかじめ分かっていても、
List list = new ArrayList();
と書いておくのが、作法として望ましい。(もしかしたら、事情が変わって別の実装に差し替える可能性があるから)
インターフェースは動作を定義しない
Javaのインターフェースは、操作のセットを定義するものであって、そのオブジェクトの動作や特性を定義するものではない。本当に、シンプルに、あるオブジェクトが理解するメッセージを列挙するだけの機能しかなく、その中に動作に関する定義を紛れ込ませる隙はないからだ。*1
もし、どんなにドキュメントやコメントでそれを定義したところで、コンパイラはそれを無視する。だから、頭のいかれたオブジェクトが、addしたオブジェクトを破壊してしまったところで、インターフェースの意味からは、その動作が間違っているとは言えない。
もしも、動作に関する定義を記述したければ、以下のような内容をインターフェースの記述に含んでいる必要がある。(記法はオリジナル*2。また、Listの全ての動作を定義しているわけではない。)
let list as java.util.List satisfy for any x given list.add(x), i = list.size() -1 then x == list.get(i) satisfy for any i if and only if true == list.isEmpty() then null == list.get(i)
しかし、実装に本当に興味がないこともある
数なんてどうか?
整数が欲しいことがある。しかし、32bit整数は欲しくない。とはいえ、32bitの範囲に収まるなら32bit整数として計算しておいてもらった方が、余分なリソースを食わないので嬉しい。そういうインテリジェンスをVMなりランタイムなりの求めたい。
そういう時は、確かに、(以下はJavaっぽいですが、Javaではありません)
Integer one = new Integer(1);
という書き方をして、実際には、Int32型オブジェクトができていてくれたりすると嬉しいかもしれない。下のような書き方はしたくない。
Integer onebillion = new Int32(1000000000); Integer tenbillion = new BigInt(10000000000)
そして、計算しているうちに32bitを超えた場合には、自動的にBigInt型オブジェクトに変わっていると非常に嬉しい。
しかし、以下のようにオブジェクトを生成した場合、
Int32 one = new Int32(1);
これは常にInt32でいて、オーバーフローした場合は、32bit整数として自然な形で桁あふれして欲しい。決して、自動的にBitInt型オブジェクトに変わらないで欲しい。