ローカル変数の型 #4

まだ続くのか?

変数宣言の変更コストについて話をしているんじゃないです。変数の型を抽象型で指定すれば実装クラスを変更してもよいことが明確になりますが、型を具象クラスで指定すればその利点がなくなることを問題にしています。これはローカル変数に限りません。
また変更コストについていえば、抽象型で指定した場合は具象クラスをいくらでも変更してよいことがすぐにわかるので、変更コストは低いです。しかし具象クラスで指定した場合は、変更していいかどうかを調べる必要があるので、変更コストはより高くなります。

そんなことはないと思うなぁ。実装を差し替えてもまともに動くようにするにはそのように実装しないといけないわけで、抽象型で宣言すれば良いという話ではないよね。例えば

List<String> list = new LinkedList<String>();

とあった場合を想像すれば良い。これを ArrayList に替えてもいいかといえば、結構な確率で良くない。そもそもメソッドシグネチャの差が問題ならそんなのコンパイラなり IDE なりがさっくり指摘してくれるわけで。
もうひとつ例を挙げれば、

List<Integer> xs = new ArrayList<Integer>();
List<Integer> ys = new ArrayList<Integer>();

// do something

int len = Math.min(xs.size(), ys.size());
for (int i = 0; i < len; i++) {
    foo(xs.get(i), ys.get(i));
}

とかこんなの。これを List#get(int) を禁止して書くのは結構面倒だから、メソッド内で new している xs/ys が RandomAccess であることを前提にコードを書いてしまうということは多分にある話ではないかなぁ。この辺はスタイルの違いなのかもしれないけど。
あと、BufferedReader のコード例は誤解というか書き方が悪かった。あれは、

  • Reader で宣言したオブジェクトがあって、実態は BufferedReader
  • コードを書いている途中で BufferedReader#readLine が必要なことに気づく

という場面で普通はキャストするんでなくて、宣言を変えてしまう、という話。
じゃぁ、宣言を変更することと、実装を替えることはどっちが多いのかって、多分どっちも問題になるほど多くはないというオチ。

しかし、ローカル変数の型とどこが結合しているのか良く分からない。メソッド内の他のコード?でもメソッド内のコードってこれ以上ないくらい依存しあっているものだしなぁ。違うよなぁ。