Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby mixin override method clarification

I've just faced this behavior I don't really understand.

module M
  def foo
    "module_foo"
  end
end

class C
  def foo
    "class_foo"
  end
  include M
end

puts C.new.foo

Why does C.new.foo actually return class_foo ? I was pretty much sure that method should be overridden by the one in module. Another thing, replacing "class_foo" with super makes C.new.foo return `"module_foo"

That actually looks like module is somehow included before the class instance method is defined. Could you please clarify?

like image 880
Vlad Khomich Avatar asked Mar 22 '12 17:03

Vlad Khomich


2 Answers

From Programming Ruby section on mixins:

In fact, mixed-in modules effectively behave as superclasses.

So what you experience is normal. your Module M is a superclass of your class C

Therefore your foo method in class C overrides the foo method in module M

like image 133
Aurélien Bottazini Avatar answered Nov 08 '22 00:11

Aurélien Bottazini


Here's how ruby does method lookup:

  1. receiver's singleton class;
  2. receiver's class;
  3. any included modules methods;
  4. repeat lookup in in the receiver's superclass;
  5. if no method was found at all, method_missing call;

You can find more details here: http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html

Therefore, to find a method, Ruby goes in the receiver's class, and from there it climbs the ancestors chain until it finds the method. This behavior is also called the "one step to the right, then up" rule: Go one step to the right into the receiver's class, and then up the ancestors chain, until you find the method. When you include a module in a class (or even in another module), Ruby creates an anonymous class that wraps the module, and inserts the anonymous class in the chain, just above the including class itself.

like image 31
andersonvom Avatar answered Nov 08 '22 02:11

andersonvom