I was under the impression that include and extend were basically
module-level
and object-level versions of the same thing, that including a module at
the
class level had the same effect as extending an object. But it seems
there is a
big difference:
class Foo
include Enumerable
end
class Bar
def initialize
extend Enumerable
end
end
(class << Foo.new;self;end).ancestors #=> [Foo, Enumerable, Object,
Kernel]
(class << Bar.new;self;end).ancestors #=> [Enumerable, Bar, Object,
Kernel]
This makes a whole world of difference when you want to wrap certain
methods
with additional functionality. In such cases you have to use extend
(or ugly
techniques like aliasing the old method). Why the difference? In what
cases
should I use include and what cases should I use extend?
Daniel
Hi –
On Tue, 11 Jul 2006, Daniel DeLorme wrote:
extend Enumerable
end
end
(class << Foo.new;self;end).ancestors #=> [Foo, Enumerable, Object, Kernel]
(class << Bar.new;self;end).ancestors #=> [Enumerable, Bar, Object, Kernel]
This makes a whole world of difference when you want to wrap certain methods
with additional functionality. In such cases you have to use extend (or
ugly techniques like aliasing the old method). Why the difference? In what
cases should I use include and what cases should I use extend?
It’s understood that if you extend an object, it’s because you want
to put the module ahead of the object’s class in the method look-up
path. Otherwise, you’d put the functionality you want in the class
By the same token, it would be very unusual to put extend in
initialize.
Basically you use extend when you want to control behavior via modules
on a per-object basis. A common use is for classes:
module M
def meth
puts “Hi”
end
end
class C
extend M
end
C.meth # Hi
obj.extend(Mod) is equivalent to:
class << obj
include Mod
end
(or very nearly equivalent; there may be some arcane difference I’m
not remembering). So it’s all really include operations – but, when
done with extend, the class doing the including is a singleton class.
David
In the first case, the proxy that refers to the Enumerable module is
inserted between Foo class and Object class. In the second case, an
instance of a Bar class during initialization receives a new class
which is the same proxy object and this proxy’s superclass is Bar
class. BTW, check out this book at http://rhg.rubyforge.org. It has a
very nice chapter about internal structure of Ruby object model.
Kent.