Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected value of __callee__ when including a module – is this a Ruby bug?

When invoked via a method created by alias_method, __callee__ ignores the name of the old method (here xxx) and returns the name of the new method, as below:

class Foo
  def xxx() __callee__ end
  alias_method :foo, :xxx
end

Foo.new.foo # => :foo

This behavior holds even when xxx is inherited from a superclass:

class Sup
  def xxx() __callee__ end
end

class Bar < Sup
  alias_method :bar, :xxx
end

Bar.new.bar # => :bar

Given both of the above, I would expect that the same behavior would hold when xxx is included via a module. However, that is not the case:

module Mod
  def xxx() __callee__ end
end

class Baz
  include Mod
  alias_method :baz, :xxx
end

Baz.new.baz # => :xxx

I expect the return value to be :baz, not :xxx.


The above code was executed using Ruby 2.3.1p112. Is this a bug in the implementation of __callee__? Or maybe of alias_method? And if not, can anyone explain why module inclusion behaves differently?


UPDATE 1

I've posted this to the Ruby bug tracker to try to stir up an answer.


UPDATE 2

Apparently, I'm not the only one to be surprised by this issue. I wonder whether Revision 50728 (which was meant to solve Bug 11046: __callee__ returns incorrect method name in orphan proc) might be related.

like image 587
user513951 Avatar asked Feb 09 '16 00:02

user513951


2 Answers

You can see the difference between __callee__ and __method__ in Ruby's Kernel module.

The difference is the calls prev_frame_callee() and prev_frame_func(), respectively. I found these function definitions at http://rxr.whitequark.org/mri/source/eval.c

In short, Foo and Bar are immediately calling the aliased methods foo and bar (which are names for xxx), while Baz has to find Mod and call xxx from Mod. __method__ looks for the original called method's id, while __callee__ looks for the closest called method's id to the __callee__ call. This is better seen in eval.c at lines 848 to 906: look for the difference in the two methods on the return calls similar to <something> -> called_id vs <something> -> def->original_id.

Also, if you look at the Kernel from version 1.9.3, you will see that the two methods originally were the same. So, at some point, there was a purposeful change between the two.

like image 190
fkantner Avatar answered Nov 08 '22 01:11

fkantner


This was a bug, and it was closed 3 days ago with this note:

Seems fixed by r56592.

like image 29
user513951 Avatar answered Nov 08 '22 03:11

user513951