Bug #11120
closedUnexpected behavior when mixing Module#prepend with method aliasing
Description
I'm not completely sure myself if this should be considered a bug, but at least it should be up for discussion.
I stumbled upon this behavior when migrating some code using alias chains to Module#prepend.
Consider the following code:
# thingy.rb
class Thingy
def thingy
puts "thingy"
end
end
# thingy_with_foo.rb
module ThingyWithFoo
def thingy
puts "thingy with foo"
super
end
end
Thingy.prepend(ThingyWithFoo)
# thingy_with_bar.rb
class Thingy
alias_method :thingy_without_bar, :thingy # Wont't alias create an alias for Thingy#thingy but ThingyWithFoo#thingy instead
def thingy_with_bar
puts "thingy with bar"
thingy_without_bar # Expected to call original Thingy#thingy method but will call prepended method instead
end
alias_method :thingy, :thingy_with_bar
end
# some_file.rb
Thingy.new.thingy # raises: stack level too deep (SystemStackError))
In a nutshell when calling super
from ThingyWithFoo#foo
it will call thingy_with_bar
method, and this method will call back to ThingyWithFoo#foo
by invoking thingy_without_bar
, thus producing an endless loop.
This situation arises because alias_method
is producing an alias not for the Thingy#thingy method the but for the upper method from ThingyWithFoo
instead. May be this behavior could be considered correct, I'm still not sure, but it will probably became a problem for source code migrating from alias chains to use Modue#prepend
, specially when other active gems could potentially still be using alias chains themselves without the user knowledge.