3

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?

Chris Rice
  • 1,390
  • 11
  • 16
  • The following question has a detailed answer that might also be helpful: http://stackoverflow.com/questions/23848667/ruby-method-lookup-path-for-an-object – Powers May 25 '14 at 06:22

2 Answers2

8

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
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
3

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 :)

Stefan Kanev
  • 3,030
  • 22
  • 17
  • I think your sentence "What's missing in your model is Bar.superclass inherits Foo.superclass" should be changed to "What's missing in your model is Bar.singleton_class inherits from Foo.singleton_class". – Powers May 24 '14 at 18:37