リスコフの置換原則

拙著「コーディングを支える技術」の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を書きなおすことができない状況になっていたりするわけです。

さいごに

このエントリーではリスコフの指摘した「置換原則を満たしていない場合に起こる問題」を、時系列に並べて解説してみました。書籍の方は紙面の制約がありますが、なんとかわかりやすくなるように修正したいと思います。

拙著「コーディングを支える技術」の読者のみなさんから頂いたご質問・ご感想には、このような感じで補足記事を書いて行きたいと思っています。おきがねなくご質問・ご感想をお寄せ下さい。

拙著に関する他のエントリーは「「コーディングを支える技術」著者公式ページ」からたどれるようにします。