Ruby 2.2.0 now warns against a circular argument reference. It is pretty simple to demonstrate and pretty difficult to explain so I’ll just present some code snippets.

The first example shadows a function (which I have encountered in one of the open-source projects I’m involved with):

def foo
  42
end

def bar(foo = foo)
  foo
end

puts bar.inspect

On ruby 2.1 it just prints 42. On ruby 2.2 though:

-e:5: warning: circular argument reference - foo
nil

The warning refers to the def bar(foo = foo) definition. If you remember a = a with a being an uninitialized variable, initializes a with the value of nil. Ruby 2.1’s function definitions though was not fully following this logic and that disparity was utilized by some developers as a feature. Now in ruby 2.2 this has been fixed and recognized properly.


On the other hand when shadowing a variable instead of a function:

foo = 42

def bar(foo = foo)
  foo
end

puts bar.inspect

On ruby 2.1 it fails with:

-e:3:in `bar': undefined local variable or method `foo' for main:Object (NameError)
        from -e:1:in `<main>'

But on ruby 2.2, it recognizes the circular reference:

-e:3: warning: circular argument reference - foo
nil

To figure out if one’s code exploits this feature/bug, one can simply run the following regexp:

ag 'def +[A-Za-z._!?]+(\(| +)([^)]+, *)?([a-z_]+) *[=:] *\3[^a-z_!?.]'

I’m assuming using The Silver Searcher and not filtering any files based on extension. Otherwise, just replace ag with git grep and you are good to go.


Changelog:

  • 8th October 2015 – Update regexp to account for keyword arguments and methods ending in “!”, “?” – thanks to Alan & Andreas