ruby における unless の利用が許容される範囲 (個人的見解)


Overview

ruby では unless という構文が使えますが、これが時に可読性を著しく下げてしまう要因になってしまうなあ...と常々思っていました。

あくまで個人的見解ですが unless を使っても良い条件と、あまり使わない方が良いかなと思っている条件をまとめてみます。

ご意見などありましたらご遠慮なくいただけると幸いです。

ruby における unless

そもそもの unless の役割を最初にまとめます。

いろんな言語で使われている条件判定の一つに if があると思います。この if は、条件式が true と判定される場合、条件の中に記述した処理を通るというものです。

if condition
  # comes here when the result of condition is true
end

翻って、unless とは、条件式が false と判定される場合、条件の中に記述した処理を通るというものです。

unless condition
  # comes here when the result of condition is false
end

unless がよく使われるケース

ruby だと即時復帰の文化が色濃い気がしているので、以下のように one liner で使うケースが多いかなと思います。

return unless condition # when the result of condition is false, return!

で、この condition がどんな条件かによって使っていいケースかそうでないかに分かれます...。

unless を使わない方がいい条件式

cond_1 = true
cond_2 = false

puts 'comes here #1' unless cond_1 && cond_2   # 1
puts 'comes here #2' unless cond_1 || cond_2   # 2
puts 'comes here #3' unless !cond_1 && cond_2  # 3
puts 'comes here #4' unless !cond_1 || cond_2  # 4
puts 'comes here #5' unless cond_1 && !cond_2  # 5
puts 'comes here #6' unless cond_1 || !cond_2  # 6
puts 'comes here #7' unless !cond_1 && !cond_2 # 7
puts 'comes here #8' unless !cond_1 || !cond_2 # 8

このスクリプトを実行すると、何番が出力されると思いますか?
答えは [#1, #3, #4, #7] なのですが、自分はよーく考えないと分からないです。。。(特に条件に否定が入っている場合)

ということで個人的に unless を使わない方が個人的にいいと思う条件式は、条件を複数含む条件式です。

unless を使っても良い条件式

反対に unless を使ってもいいと思う条件式は、以下のように条件が一つの場合です。

cond_1 = true
cond_2 = false

puts 'comes here #1' unless cond_1   # 1
puts 'comes here #2' unless cond_2   # 2
puts 'comes here #3' unless !cond_1  # 3
puts 'comes here #4' unless !cond_2  # 4

これだと、条件式の結果が false になっているものなので [#2, #3] ということがすぐわかります。

unless の意義を考える

@scivola さんのご意見を受けて

そもそも条件式に ! を使わなくて済むように,というのが unless の存在意義の一つ

は確かにその通りだなと思いました。

cond_1 = true

puts 'comes here #3' unless !cond_1

と書いて unless! で二重否定の条件になるくらいであれば、大人しく

cond_1 = true

puts 'comes here #3' if cond_1

if を使った方がいい気がします。

まとめ

ということで、unless の利用について個人的見解をまとめてみると以下のようになります。

  • 条件式の条件が一つの場合は unless を使っても大丈夫。
  • 条件式の条件が複数はなるべく unless ではなく if を使うことを検討する。
  • unless! で二重否定の条件になるくらいであれば if を使うことを検討する。

おまけ

unless から if の変換に ド・モルガンの法則 を利用すると楽に変換することができます。

unless A || B = if !A && !B

unless A && B = if !A || !B

unlessド・モルガンの法則 については、
@jnchito さんの記事がとてもわかりやすかったのでリンクを載せさせていただきます