Before voting for closing due to question duplication I want to say that my question is really simple one (not asked in above mentioned questions).
There are two modules, one defines module method using extend self
, another defines mixin method.
module A
extend self
def module_a_meth
"Called module_a_meth"
end
end
module B
def module_b_meth
"Called module_b_meth"
end
end
There is a class, where I both include
and extend
these modules:
class Test
include A
extend A
include B
extend B
end
When we include
ing module, its methods become class' instance methods, when extend
ing - class methods.
Question:
it doesn't matter for class, if methods in module defined as module methods or mixin methods, right? I mean, when include
d - EVERY method (either module methods or mixin methods) become instance methods, and when extend
ed - either become class methods.
If I'm wrong - where is the difference?
obj = Test.new
puts obj.module_a_meth
puts obj.module_b_meth
puts Test.module_a_meth
puts Test.module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
Please start your answer with Yes or No, since my question implies this type of answer :).
Regardless of whether you are using extend
or include
you are always copying over instance methods. The difference is where those instance methods live.
When you call Class#include
you are "copying" all of the instance methods in the module to be instance methods in the class. It's similar to how inheritance work, and if you call Class#ancestors
you'll see the module there.
When you call Object#extend
you are copying all of the instance methods of the module to the object's singleton class. This is a class reserved just for this object instance that is created at runtime. This is how you get "class methods" (e.g. MyClass.hello_world
); by adding them to the class's singleton. You can also do things like extend a particular object instance (e.g. s = String.new; s.extend(SomeModule); s.hello_world
)
There are some other differences too. The context binding is different depending on whether you use extend
or include
. extend
doesn't cause the module to show up in the ancestor chain while include
does.
When trying to add both "class" and instance methods, one common pattern you'll see is doing things like this which uses the included
callback to extend the base class with a ClassMethods
module:
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def hello_world
end
end
end
ActiveSupport::Concerns
also abstracts this pattern allowing you to add both instance and "class" methods in one call.
I personally prefer having modules only work with instance methods and using singleton methods (e.g. def self.my_method
) to have scoped methods (sort of like how you would use private methods). This allows consumers to use either extend
or include
however they want and have it work as expected.
I'm not sure if that answers your question or not, but there's some info for you
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With