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型オブジェクトに変わらないで欲しい。

*1:もっとも、Javaの開発者のなかでも、ここの理解には混乱があるようで、java.lang.Cloneableインターフェースなどは、明らかにインターフェースが持ち得ない何か(つまり動作の定義)を期待している。

*2:オリジナルの記法が、括弧を外したLispに見えるのは気のせいでしょうか・・・