読者です 読者をやめる 読者になる 読者になる

転職した

調べた事、学んだ事、思った事、考えた事を個人的にまとめているだけなので内容は保証しないYO!

Rubyのifで=を使った時に警告がでるときでないとき

Effective Ruby

この例のようにif式の条件部で代入 することは一般的である。逆に言えば、本当は"=="を使うべきところでうっかり"="を使ってしまうこともある。この種のミスには気をつけたい

Effective Ruby p7

と書かれていて、あれ、ifで=を使ったら警告でなかったっけ?*1 と思って調べてみた。

#!/usr/bin/env ruby -W -v

a = 0
if a = 1
end

b1 = 1
b2 = 1
if b1 = b2
end

if $c = 1
end

d = 0
if d = 'hoge'.match(/hoge/)
end

e = 0
if e = 'hoge'.upcase
end

class Hoge
  attr_accessor :f

  def g
    if @g1 = 1
    end
  end
end

hoge = Hoge.new
if hoge.f = 1
end

hoge.g

h = nil
puts h = false ? 1 : h.class.to_s

このようなコードを実行してみる。最後の例は、下記のコメントで指摘されていたので入れてみた。

if式 / if文 の条件節で、左辺に定数を書くべき言語はあるか? @ajiyoshi.gist

実行結果は下記の通りである。

ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-darwin14.0]
./hoge.rb:4: warning: found = in conditional, should be ==
./hoge.rb:12: warning: found = in conditional, should be ==
./hoge.rb:27: warning: found = in conditional, should be ==
NilClass

この通り、下記の場合しか警告がでない。

if x = 1
end

if $c = 1 
end

  def g
    if @g1 = 1 
    end 
  end 

条件演算子の例については、見ての通りで、演算子の評価順の問題である。y = falseが先に評価されるのであれば、FalseClassと出力されるはずだが、そうなっていない。というか、val = bool ? a : bという代入はCなどではよく使われるので、考慮不足な指摘な感じが否めない。

まとめ

警告がでるのは下記の場合に限られる(ようだ)。

  • 左辺が変数であり、右辺が1や'hoge'のような即値の時の代入

ゆえに、下記のような場合は警告がでない。

  • 右辺が即値でない場合
  • 代入メソッドの呼び出しの場合

右辺が即値の場合、絶対に実行されるか、絶対に実行されないのいずれかになるため、ミスの可能性が極めて高いといえる。ゆえに警告がでるのは妥当だろう。 ところが、代入メソッドの場合、右辺が即値でも警告はでない。代入メソッドの戻り値によるからかと思ったが、代入メソッドは引数で指定された値を返すという挙動をする。つまり、puts o.v = 1とした場合、o#v=(v)で何を返していても1が出力される。なので、代入メソッドの場合も警告がでる方が妥当だと思うのだがなぜかでない。よく分からない挙動である。

Effective Ruby

Effective Ruby