LoginSignup
5
5

More than 5 years have passed since last update.

引数省略時の値を引数と同名のメソッドで設定していると Ruby 2.2 で動かなくなる場合がある

Last updated at Posted at 2015-02-23

結論から言うと。

  • 仮引数を foo = foo のように記述した場合の挙動が Ruby 2.2 で変わった (修正された)
  • foo = foo() または foo = self.foo にすれば 2.1 と同じ挙動になる
  • 実行中 warning: circular argument reference という警告メッセージが出たら、たぶんまともに動かないので注意
  • Rails 4.1.2 未満は Ruby 2.2 に対応していない

経緯

Rails 3 のアプリケーションを Ruby 2.2.0 でテストしたら、謎の例外が起きた。

Failure/Error: Unable to find matching line from backtrace
     TypeError:
       wrong argument type nil (expected Symbol)

例外が起きる前に下記のような警告が表示されている。

.../lib/active_record/associations/has_many_association.rb:79: warning: circular argument reference - reflection

該当箇所の Rails 3.2.21 のコードをみるとこんな感じ。

def inverse_updates_counter_cache?(reflection = reflection)
  ...
end

Rails 4.2.0 だとこうなってる。

def inverse_updates_counter_cache?(reflection = reflection())
  ...
end

debugger でみてみると、Rails 3.2.21 の書き方では reflection は nil になってしまっている (reflection メソッドは attr_reader :reflection で定義されており、@reflection にはオブジェクトがある)。

どうも、引数省略時の値を仮引数と同名のメソッドで設定しようとしている場合に、メソッドを呼び出すのではなく、ローカル変数を参照するように変わったらしい。それで、reflection() と明示的にメソッド呼び出しの書式にすることで、問題を回避しているものと思われる。

blame を見てみると、次のコミットで修正されたようだ。

ここから、bugs.ruby-lang.org を参照しているので見てみる。

元の挙動は bug であるとされている。確かに例に挙げられているとおり、通常は foo = foo としたら右辺はローカル変数の参照になるので納得できる。

Yes. It was a bug.
An assignment creates a variable and it hides same name method in its RHS, as you can't call foo method inside bar method:

def foo; 'foo'; end

def bar
  foo = foo # nil
end

https://bugs.ruby-lang.org/issues/9593#note-5

また、同じコメントで、() を後置することで、メソッド呼び出しであることを明示する方法が紹介されている。

Always you can call the method explicitly with ().
https://bugs.ruby-lang.org/issues/9593#note-5

文法上メソッド呼び出しであることが明示されればよいので、self.reflection のように self. を前置してもよい。

あとで気付いたが、2.2.0 リリース時の NEWS でも言及されていた。

5
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5