Question

How is it that Ruby allows a class access methods outside of the class implicitly?

Example:

class Candy
    def land
        homer
    end
end

def homer
    puts "Hello"
end

Candy.new.land #Outputs Hello
Was it helpful?

Solution

The definition of the "homer" method is adding the method to the Object class. It is not defining a free function.

Class Candy implicitly inherits from Object, and so has access to the methods in Object. When you call "homer" in the "land" method, the method resolution can't find a definition in the current class, goes to the super class, finds the method you have added to Object, and calls it.

OTHER TIPS

A simple way to find out what happens

  1. What classes/modules are searched to resolve methods used in Candy objects?

    p Candy.ancestors #=> [Candy, Object, Kernel]

  2. Does Candy have method called homer?

    p Candy.instance_methods(false).grep("homer") #=> []

    p Candy.private_instance_methods(false).grep("homer") #=> []

  3. OK Candy does not have any method called 'homer'.

  4. What's next in the lookup chain (see 1) => "Object"

  5. Does Object have a method called "homer" ? p Object.instance_methods(false).grep("homer") #=> []

    p Object.private_instance_methods(false).grep("homer") #=> ["homer"]

Candy has Object in its lookup chain which in turn has a private instance method "homer" so method resolution succeeds

The def statement always defines the method in the class of whatever self is at the point of definition

  1. What is self just before homer is defined ?

    p self #=> main def homer puts "Hello" end

  2. So what is its type ?

    p self.class #=> Object

Which is why homer ends up on Object

Technically, the definition of the homer method is actually on the Kernel module which is mixed into Object, not on Object directly. So when homer is not a local variable or an instance method defined on Candy, the Ruby method inheritance chain is followed up through Object and then to the mixed-in Kernel module and then this code is run.

Edit: Sorry, I don't know why I thought this. It appears that the method really lives on Object. Not sure it makes too much of a difference in practice but I should have confirmed things before posting.

Ruby has no free-floating functions. Every method belongs to some object. Methods that you def at the top level are actually becoming instance methods of class Object. Because everything is an Object at some level, all objects have access to Object's instance methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top