Re: ローカル変数の型 #4

前のエントリの繰り返しになりますが、「ローカル変数ならアップキャストしなくてもいいよ」ということには反対していません。「ローカル変数の型宣言はできる限り特定しておいたほうがよく、そのためにアップキャストしないほうがいい」とおっしゃってるから、それはおかしいのでは? と指摘しているだけです。それをふまえた上でお読みください。

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

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

とあった場合を想像すれば良い。これを ArrayList に替えてもいいかといえば、結構な確率で良くない。

ローカル変数の型 #4 - odz buffer

これも List を使うべきではない場合ですよね。LinkedList であることが必要な場面では型として LinkedList を指定すべきで、List を指定すべきではないです。
また何度も言いますが、問題にしているのは『ローカル変数ではキャストすべきでない (型宣言はできる限り特定しておいたほうがよい)』という主張です。LinkedList で指定すべき場面があるからといって、List で指定して構わない場面でも必ず LinkedList を使うべきというのはおかしいと言っているんですが。
こちらの説明が悪いせいか、なかなか分かってもらえないようで。すみません。

そもそもメソッドシグネチャの差が問題ならそんなのコンパイラなり IDE なりがさっくり指摘してくれるわけで。

ローカル変数の型 #4 - odz buffer

メソッドシグネチャが合っていれば大丈夫とかいう話をしているわけではないんですが。ひとつ前のエントリになりますが、

一般的な指針としてはこれですね。付け加えるなら add と contains しか使っていないから Collection と宣言するのが適切かと言えばそうでもないとか。つまり型はインターフェース以外のことも語っていたりするという。

ローカル変数の型 #3 - odz buffer

これも同じですよね。Collection のメソッドしか使ってないなら Collection で宣言しろなんて誰も言ってないです。Collection のメソッドしか使ってなくても、List であることが必要なら List で宣言すべきです。

もうひとつ例を挙げれば、

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 であることを前提にコードを書いてしまうということは多分にある話ではないかなぁ。この辺はスタイルの違いなのかもしれないけど。

ローカル変数の型 #4 - odz buffer

これも、xs/ys が RandomAccess であることを前提にするなら、List で宣言すべきではない場面ですよね。メソッドシグネチャに関係なく。そういう場面があるからといって、RandomAccess でなくて構わない場面でも List を使うべきではないという主張がおかしいのではないでしょうか。
別に、ローカル変数を具象型で宣言することに反対しているのではないです。ローカル変数はすべてキャストすべきではないというような主張をされているから、それは違うんじゃない? と聞いているんですが。そんなにわかりにくいでしょうか。

じゃぁ、宣言を変更することと、実装を替えることはどっちが多いのかって、多分どっちも問題になるほど多くはないというオチ。

ローカル変数の型 #4 - odz buffer

これは何を主張されているのかわからないんですが、宣言するのは Reader でも BufferedReader でもどっちでもいい、ということでしょうか。もしそうなら、何度も書いてますが多いに同意します。ただ、それは「ローカル変数の型宣言はできる限り特定しておいたほうがよい」とは違いますよね。
odzさん達の説明はどれも、「ローカル変数ではキャストしてもしなくてもよい」または「キャストしないほうがよい場面がある」ことは示していますか、「ローカル変数の型宣言はできる限り特定しておいたほうがよく、そのためにキャストしないほうがいい」ということの理由にはなってないです。

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

http://d.hatena.ne.jp/odz/20080311/1205239054

もう一度説明します。これで分かっていただけないようでしたら、こちらの説明能力が悪いので、申し訳ありませんがこれ以上説明できません。

// Reader であればなんでもよい。よって例えば BufferedReader を
// 使うように変更してもよいことがよくわかる。
Reader reader = new FileReader('foo.txt'));

// あえて FileReader に限定している。BufferedReader など別の型に
// 変更していいかどうかは、他の箇所も調べて判断しないといけない。
FileReader reader = new FileReader('foo.txt'));

int ch;
while ((ch = reader.read()) >= 0) {
    System.out.println((char)ch);
}


もうなんか、わざとはぐらかされているように思えるのですが、もしよければ以下の質問に答えていただけますか。なんか前提がおもいっきり違うようにしか見えないので。

  1. 「アップキャストしてもいい (しなくてもいい)」と、「アップキャストしないほうがいい (してはいけない)」とは違うものである、という認識はあってますか?
  2. アップキャストしてもいい場面と、アップキャストしないほうがいい (してはいけない) 場面の両方が存在する、という認識はあってますか?
  3. アップキャストしないほうがいい場面があるからといって、アップキャストしていい場面でもそれを「すべきでない」とするのはおかしい、という認識はあってますか?
  4. アップキャストしていい場面でも、ローカル変数であればアップキャストしなくても構わない、という認識であってますか?
  5. 「ローカル変数の型宣言はできる限り特定しておいたほうがよい」という主張は、ローカル変数ではアップキャストすべきでないことを意味している、という認識であってますか?


今の状態だと双方にとって有益にはならないので、お互いの認識が一致しているかを確認するためにも、お手数をかけますがよろしくお願いします。