Include vs. extend

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 --

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?

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
:slight_smile: 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

···

On Tue, 11 Jul 2006, Daniel DeLorme wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS, the Ruby book for
                                                     Rails developers
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

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.

···

On 7/10/06, Daniel DeLorme <dan-ml@dan42.com> wrote:

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

--
Kent
---