Java World とかで妙に異質な連載をしていることで定評がある檜山さんがこのへんでBlogをつけていて管理人は密かにウォッチしているのですが、最近はEiffelをネタに共変性の議論をしているようです。

この檜山さんという人、昔XML関係の活動をしていたときに何度かメール交換やら、飲みをご一緒やらさせていただいた仲なのだが、なんというか、すごい人なのである。

何がすごいかってーと、まあ説明をするよりも氏のブログで プログラマのための「ゲーデルの不完全性定理」とかそのへんのエントリを見てもらえれば一発かと。
もう、記事の発想が尋常じゃない。一線突き抜けちゃってる感じ。
僕の中での尊敬するオトナ(ここは漢字で書いてはいけないのである。ゼッタイ)ベスト10に入るほどのお人である。

ま、それはさておき、covariantの話である。

共変の継承の問題点:再確認


List list = new IntegerList();
list.add("Hello");
list.add(new Date());


IntegerList型では、追加できる項目を型により制約しているので、list.add("Hello");もlist.add(new Date());も許されません。とは言っても、コンパイラがこのテの問題を完全に検出するのは不可能なので、実行時の型エラーとなるでしょう。

リスコフの置換原則(の教訓としての解釈)は、「スーパータイプのインスタンスを、サブタイプの対応するインスタンスに置き換えても、何の問題も起きないようにせよ」と主張しているので、IntegerList extends List という共変の継承はリスコフの置換原則を破っています



おっしゃるとおり。

んが、実はJavaではこの原則破りルールを配列では採用していて
subclass が superclass を継承すると、自動的に
subclass[] が superclass[] のサブクラス扱いになり、代入できてしまいます。

だから、


class base{}
class derived extends base{}

public class array_covariant {
public static void main(String[] args) {
base[] bases = new derived[2]; // あああ、これがコンパイルエラーにならない
bases[0] = new base(); // ここで ArrayStoreException

}
}


このコードがコンパイルエラーにならずに実行時エラーになってしまいます。
実行時にチェックしてくれるので、まだマシという意見もありますが、
本来コンパイル時に分かるはずのエラーなのにぃぃぃ
とか考えると鬱ですな。


・・・・という議論がJDK1.0が出る直前ぐらいにネットでよく見かけたけど
今日 Eclipse3.11(JDKだと1.4.x) で試したら直ってなかった。
もう10年も立つのだが。

Javaって文法の互換性には本当に保守的じゃのう・・・

#てゆーか、自分が10年も前のことを懐かしげに語るような年になったことが驚きだだだ