ド・モルガンの法則
if not (logged_in and has_permission) が読めない
ログイン済みで、かつ権限がある人だけ通したい。素直に書くと、拒否する側はかたまり全体の否定になります。
Python
if not (logged_in and has_permission):
deny()読むときに、頭の中で 2 回ひっくり返すことになります。and の結果をいったん作って、それを否定する。条件が 3 つ 4 つと増えると、レビューで誰も追えなくなります。
かたまりの外にある not を、中へ配ってしまえば読みやすくなります。その配り方を決めたのが、ド・モルガンの法則です。
否定を内側に配る 3 手順
手順は次のとおりです。
- かたまりの外の
notを消して、中の項ひとつひとつにnotを付ける - 真ん中の
andをorに、orをandに入れ替える - 項が比較式なら、
notを付けたままにせず、反対向きの比較に直す
さきほどの条件に当てはめると、こうなります。
Python
if (not logged_in) or (not has_permission):
deny()「ログインしていない、または、権限が無い」と、そのまま日本語で読めるようになりました。項が 3 つ以上あっても手順は同じで、全部に not を配って、間の演算子をすべて入れ替えます。
なぜ and と or が入れ替わるのか
「両方そろっている、が成り立たない」を言い換えると、「どちらかが欠けている」です。全部そろう条件の否定は、1 つでも欠けていること。逆に「どちらも無い」の否定は、「少なくとも片方はある」です。
厳しい条件の否定は緩くなり、緩い条件の否定は厳しくなります。だから配ると and と or が入れ替わります。ここを入れ替え忘れると条件が狭くなりすぎて、通してよい人まで弾くか、その逆をやります。しかも動きはするので、報告が来るまで気づきません。
比較式の否定は、境界で間違える
3 番目の手順が、実は事故のもとです。not (x > 0) を x < 0 と書いてしまうと、x が 0 のときだけ結果が変わります。
> の反対は <=、< の反対は >= です。否定すると、等号の付いた側へ境界が移ります。== の反対が != なのは誰も間違えないのに、> と < は反射的に書き換えてしまいがちです。ずれるのは 1 件だけなので、テストデータの作り方によっては最後まで通ってしまいます。
要件
- (NOT a) OR (NOT b) と等価な処理を実装する
- a 1 かつ b 1 のときだけ 0 を返す
- それ以外は 1 を返す
入出力例
deMorgan(0, 0) → 1
deMorgan(0, 1) → 1
deMorgan(1, 0) → 1
deMorgan(1, 1) → 0