「5階まで行くエレベータが各階で止まると何回止まる?」とか、「長さ100メートルの歩道に5メートルおきに植木を植えると木は何本?」(植木算)とか、間違いやすいですね。
これが例外起こすのも事情は同じです。
for (int i = 1; i <= array.length; i++) {
System.out.println(array[i]);
}
勘定するとき0からはじめるか1からはじめるか、不等号にイコールが含まれるか含まれないか、限界値とは許される値か禁止される値か、などはいつだってトラブルのもとです。
さて、自分でファイルコピーコマンドを作るとします。aもbもディレクトリだとして、mycopy a b
がどう動作すべきか(仕様)を考えましょう。
次のような案がありえます。
- b/a/ を作るだけ。
- a/をルートとするツリー構造をb/a/の下に再現。
- a/の下のファイル群を b/の下の対応する位置にコピーする。例えば、a/foo.txtをb/foo.txtに。
どれもそれなりに正当化できます。その背後には、ツリーのノードを指したとき暗示される対象の曖昧さ(ゆれ)があります。つまり:
- そのノードそのもの
- そのノードを(相対)ルートとするサブツリー
- そのノードの子孫達が作るツリーリスト(ヘッジ)
仮に「a < b」を「aはbの祖先 = bはaの子孫」のことだとすると、上の解釈に対応する集合(ノードセット)は次のようです。
- { x | a = x }
- { x | a <= x }
- { x | a < x }
やっぱり、等号/不等号が“ゆれ”の原因でした。
これは、ツリーに対するパターンやオペレーションの設計をするとき、考慮すべきことです。