Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is adding a method to a module handled differently to adding a submodule?

Tags:

module

ruby

In the following example, module M is included in class A and, afterwards, re-opened to add a submodule MM, and a method. Then, it is included in class B:

module M
  def foo; "foo" end 
end

class A
  include M
end

module MM
  def baz; "baz" end 
end

module M
  include MM
  def bar; "bar" end 
end

class B
  include M
end

Instances of both A and B can access M's method regardless of when they were added, but only B has the method of submodule MM:

a = A.new
a.foo
a.bar
a.baz # => Error: not defined

b = B.new
b.foo
b.bar
b.baz

I think this is inconsistent behaviour and would like to understand why this happens.

like image 786
starfry Avatar asked Nov 01 '22 03:11

starfry


1 Answers

When you include a module M into a class C with superclass S, this is what happens:

  1. a class M' is created whose method table pointer, constant table pointer, instance variable table pointer and class variable table pointer point to M's method table, constant table, instance variable table and class variable table.
  2. M's superclass pointer is set to C's superclass (i.e. S)
  3. C's superclass pointer is set to M'

This process is repeated recursively for any modules mixed into M (and modules mixed into modules mixed into M and so forth).

This way, the linearization of the mixin hierarchy needs to only happen once, when you call include. The alternative (and this is what you seem to be expecting to happen) would be to perform this pretty expensive process for every single method call.

like image 84
Jörg W Mittag Avatar answered Nov 10 '22 20:11

Jörg W Mittag