リスコフの置換原則
拙著「コーディングを支える技術」のp.216では、リスコフの置換原則について説明しています。しかし、p.217の「条件qを満たさないTが発生する」という表現はわかりにくいようですので、ここでストーリー仕立てにして補足説明をします
今日
まず、現時点でT型の値はすべて条件qを満たしているとします。
あなたはT型の引数をとる関数fを実装したいとします。あなたはきっと「T型の値はすべて条件qを満たしている」ということを前提としてコードを書くことでしょう。
1ヶ月後
あなたはSを作ろうと考えます。S型の値の中には条件qを満たさないものもありますが、あなたはあまり意識していません。
あなたは「SはTを継承して作ると楽だな」と思ったので、そうしました。
Javaなどの言語処理系では、SがTを継承すると、T型の変数にS型の値を入れることができるようになります。つまりこの時点でT型の引数を取る関数fにS型の値を渡すことも可能になっています。
さらに1ヶ月後
あなたが2ヶ月前に実装した「T型の値を引数にとる関数f」の中で問題が起きます。
T型の値はすべて条件qを満たすはずなのに、条件qが満たされているなら起こりえないようなことが起こっています。あなたは悩みます。
あなたは原因が条件qを満たさないS型の値が引数に渡されていることだと気づきました。そこでif文で分岐して2通りの処理を書くことにしました。
これでよいのでしょうか?いや、違いますね。この2ヶ月の間に書かれた他のT型の値を扱うコードも、条件qを満たさない値だと問題が起きるかもしれません。この種のバグは、1匹目を見つけた頃には既に何十匹も物陰に潜んでいるのです。
あなたが次々出てくるバグに悩まされて、別の人に相談します。そして「なんでSはTを継承したんだ」と指摘されたとしましょう。でも、こういう状況って既にSを書きなおすことができない状況になっていたりするわけです。
さいごに
このエントリーではリスコフの指摘した「置換原則を満たしていない場合に起こる問題」を、時系列に並べて解説してみました。書籍の方は紙面の制約がありますが、なんとかわかりやすくなるように修正したいと思います。
拙著「コーディングを支える技術」の読者のみなさんから頂いたご質問・ご感想には、このような感じで補足記事を書いて行きたいと思っています。おきがねなくご質問・ご感想をお寄せ下さい。
拙著に関する他のエントリーは「「コーディングを支える技術」著者公式ページ」からたどれるようにします。