Method lookup for class singleton methods in Ruby

2020-07-22 09:34发布

I was under the impression that obj.method caused ruby to look for method thusly:

  1. Look in obj's singleton class.
  2. Look in the modules included by obj's singleton class.
  3. Look in obj's class.
  4. Look in the modules included by obj's class
  5. repeat steps 3 and 4 on the class's superclass until found
  6. If never found, call method_missing on the original object, obj.

Under this model, the only singleton class searched for the method is the singleton class of the original receiver, obj. However, this model can't explain the fact that a subclass can access its superclass's singleton methods. For example

class Foo
  def self.foo
    "foo"
  end
end

class Bar < Foo
end

Bar.foo  #=> "foo"

I'm confused because I believe this means that Foo's singleton class is at some point searched for the method foo. However, under the model above, I would expect that only Bar's singleton class would be searched for foo. Failing that, I would expect ruby to look in Bar's class, Class, and then continue crawling up the superclass chain (skipping Foo and its singleton class completely).

So my question: what is missing from my understanding of Ruby method lookup which explains the fact that a class can access its superclass's singleton methods?

标签: ruby
2条回答
疯言疯语
2楼-- · 2020-07-22 09:40

When subclassing, not only is Bar.superclass set to Foo, but the same holds true for the singleton classes:

Bar.singleton_class.superclass == Foo.singleton_class  # => true

So you're not really confused. The actual lookup is:

  1. Start with obj's singleton class.
  2. Look for instance methods down the ancestor list:
    • prepended modules (Ruby 2.0)
    • the class itself
    • included modules
  3. Repeat #2 with superclass.
  4. Repeat #1 but this time looking for method_missing
查看更多
神经病院院长
3楼-- · 2020-07-22 10:02

It's pretty straightforward. Or not really, but anyhow:

The metaclass of the superclass is the superclass of the metaclass.

Where "metaclass" is really "singleton class". What's missing in your model is Bar.superclass inherits Foo.superclass. Plain and simple :)

查看更多
登录 后发表回答