meizin
meizin

Reputation: 221

Instance method at top level

I have this code:

module M
  def m
    "hello"
  end
end

include M

m # => hello
M.m # => hello

By including M at the top level, I can call m. How come I can call M.m?

Upvotes: 0

Views: 80

Answers (3)

Stefan
Stefan

Reputation: 114208

Invoking include M at the top level includes your module in Object:

module M
  def m
    "hello"
  end
end

include M

Object.included_modules #=> [M, Kernel]

You can achieve the same with:

class Object
  include M
end

And because everything in Ruby is an object, you can send m to every object1, including instances and classes and modules (like M):

123.m        #=> "hello"
'foo'.m      #=> "hello"
String.m     #=> "hello"
Object.m     #=> "hello"
Enumerable.m #=> "hello"
M.m          #=> "hello"

1 an object in the sense of is_a? Object

Upvotes: 4

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Even more weird example:

▶ module M ; end
▶ def m ; puts '¡Hola!' ; end
#⇒ :m
▶ M.m
#⇒ ¡Hola!

So, let’s dig into object inheritance. The execution context is main. main is apparently a “special” instance of Object, propagating all the methods defined on it to be visible everywhere. Since Module instance (M) is in fact an instance of Object, it all of a sudden responds to each Object method. But we just have an Object extended with m method.

Note: module M ; def m ; end ; end; include M and def m ; end on a top level do almost the same thing: both extend Object with m method (the latter makes this method private on Object, though.)

Hope it helps.

Upvotes: 0

Jörg W Mittag
Jörg W Mittag

Reputation: 369526

The "default definee" (i.e. the module that methods defined with def and included mixins end up in) at the top-level is Object.

This means that M gets included into Object, i.e. M becomes a superclass of Object, inserted underneath Kernel. Since M is an instance of module, and Module is a subclass of Object and Object now is a subclass of M, it is possible to call M.m.

The ancestry chain of Module is:

[Module, Object, M, Kernel, BasicObject]

ergo, M is in the method lookup path for M, and therefore M.m finds the method defined in M.

Upvotes: 1

Related Questions