Ruby: Rubocopで`== true`や`== false`が怒られない理由

前置き: nil == falsefalse

Rubyの本には「条件分岐でnilfalse以外のすべてのオブジェクトがtrueとみなされます」と書かれているのが定番です。

しかし以下のとおり、nilfalse別のオブジェクトです。

nil == false #=> false

nil?も同じことをおっしゃっています。

nil.nil?    #=> true
false.nil?  #=> false
true.nil?   #=> false

nilfalseが同一視されるのは、あくまで条件分岐ifcase)のときです。

a = nil
if a
  "true!"
else
  "false!"
end
#=> "false!"

上のようにanilからfalseに変えても結果は変わりません。

Rubyにtrue?メソッドやfalse?メソッドはない

ちなみにtrue?false?といった冗長かつ悪手にしかならないメソッドはデフォルトのRubyにはありません。

true.true?   #=> NoMethodError: undefined method `true?' for true:TrueClass
false.false? #=> NoMethodError: undefined method `false?' for false:FalseClass

if a == trueのようにわざわざ== trueだの== falseだのtrue?だのfalse?だのをモロ出しに書くことを避けるのがRuby流です。

Ruby作者のお気持ちを、これまで見かけた発言などから想像してみました。仮にtrue?false?が「あり」だとすると、それを当てにしてたとえば以下のような無節操かつ欲張りさんなメソッドを書きまくって二値論理をぶち壊しにする人が続出するかもしれないということなのだと思います(外してたらすみません)。

  • truefalsenilを返し、しかもtruefalsenilの意味が異なる😨
  • truefalsenilの他にも値を返し、しかもそれぞれ全部意味が異なる😰

まあnil?があるからfalsenilの区別はやろうと思えばやれてしまうし、そうするしかない感じのメソッドもあったりしますが、あまりよろしくなさそうですね。

Ruby作者は少なくとも「Booleanクラスは作らない」と言ってたと思います(理由はちょっと違いますが↓)。

!!はRubocopに怒られる

一部地域で!!を使ってtrue/falseに揃える人もいると聞きましたが、デフォルトではRubocopに怒られます

# frozen_string_literal: true

a = false
'false' if !!a

# 上にRubocopをかける
#=> test.rb:4:12: C: Style/DoubleNegation: Avoid the use of double negation (!!).
'false' if !!a

Rubyは「ナマのtrue/false」で考えずに済むように書こう

いつもお世話になってるkazzさんが「Rubyプログラマーは明示的なtrue/falseを意識するべきではないヨ」と指摘してくれました。

言い換えれば、Rubyでは条件分岐をナマのtrue/falseで考えるのではなく、条件そのもので考えようよ、ということですね😋。上で!!がRubocopに怒られるのも、わざわざtrue/falseに還元するでないということでしょうね。

ビジネスロジックをいちいち原始的なtrue/falseに変換するのではなく、たとえば#paid?のように条件そのものをメソッド化する方が可読性も上がります。

if goods.paid == true  # 残念な書き方
...


if goods.paid?         # Rubyらしい書き方
...

本題: Rubocopで== true== falseが怒られない理由

しかし、単純に== true== falseを書く人のお尻をぺんぺんすればいいというものではなさそうです。

== true== falseという残念なはずの書き方は、意外にもRubocopに怒られません。以下は素のRubocopでエラーなしとなります。

# frozen_string_literal: true

a = false
'false' if a == false

スタイルガイド「2-61【統一】比較条件ではeven?やzero?などの述語メソッドが望ましい(==の直接使用は避ける」では、== nilといった書き方は望ましくないという記述はありますが、== true== falseが望ましくないとは記載されていません。

推測ですが、Rubocop奉行の立場としては以下のような理由があるのではないでしょうか。

  • nil?と違って、true?false?がRubyにないので、それらを使えと単純にテンプレメッセージで警告しにくい
  • 外部API様のご都合などで== true== falseと書くしかない状況が割と頻繁にある

仮にお奉行様が== true== falseを無慈悲にビシビシ取り締まったら、それを回避するためにラッパーを書くなどの手間の方が大きくなり、あちこちで一揆の火の手があがるかもしれません。

落とし所としては、== true== falseを絶対悪として根絶するほどではないにしても、この書き方をするしかなかったときに「世間に負けた」と軽く敗北感を覚える方がよさそうです。「書いたらダメ」より「書いたら負け」の精神で。

おまけ: Pythonの場合

ついでにPythonのスタイルガイドを覗いてみると、== True== Falseと書いてはいけないとありました。これも二値論理を壊さないためと思われますが、言語ではなくスタイルガイドでの制約ですね。

Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
同スタイルガイドより

なお、以下のようにPythonでは以下がすべてfalseになります。このあたりはRubyとはお家の事情が異なるということで。

  • 偽であると定義されている定数: NoneFalse
  • 数値型におけるゼロ: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • 空のシーケンスまたはコレクション: '', (), [], {}, set(), range(0)

参考: Python ドキュメント「偽であると定義されている定数

おたより発掘

関連記事

【保存版】Rubyスタイルガイド(日本語・解説付き)総もくじ

Rubyにおけるunlessとコードの読みやすさについて

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ

BPSアドベントカレンダー