Initializing instance variables in a module

Have a module:

Module Foo
   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this example? Should the add_stuff method check whether the variable has been initialized every time, or should this be done by implementing a callback like append_features or included? (That's how I'd want to do it, but it's not clear which or how...)

Thanks,
Jeff

module Foo
   def add_stuff(key, stuff)
     (@foo_the_stuff ||= {})[key] = stuff
   end
end

If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.

Ryan

···

On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:

Have a module:

Module Foo
   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)

Thanks,
Jeff

Well, it took a while but I found the answer. This is done in ActiveRecord to wrap a possible setup method in the unit tests for auto-instrumentation of fixtures. Once I knew what to look for, however, I found an old post by Florian Gross that lays out the exact answer nicely:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834

For educational purposes though, I'll explain a few things I found...

1) The append_features method is deprecated, and the included method is now the preferred callback. This method is called when a module is included, and it is passed the module that has done the including.

2) There is another callback, method_added, which is a meta-class method that is called every time a new method is defined for its class, and the symbol for the method name is passed.

So, the trick is to add a custom method_added method to the meta-class of the class that does the including by extending it in the included callback. The custom method_added needs to redefine initialize after it is added so that it does the custom setup, then calls the original.

Phew... Too bad we can't just have another callback that lets us do this easily. Maybe that feels too much like multiple inheritance or something?

module Foo
   def module_initialize
     @myvar = Hash.new {|k,v| k[v] = }
   end

   def bar(key)
     @mybar[key]
   end
end

Isn't this a common thing to want?

-Jeff

Jeff Rose wrote:

···

Have a module:

Module Foo
  def add_stuff(key, stuff)
    @foo_the_stuff[key] = stuff
  end
end

class Bar
  include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this example? Should the add_stuff method check whether the variable has been initialized every time, or should this be done by implementing a callback like append_features or included? (That's how I'd want to do it, but it's not clear which or how...)

Thanks,
Jeff

Hi,

···

In message "Re: initializing instance variables in a module" on Tue, 23 May 2006 00:51:35 +0900, Jeff Rose <rosejn@gmail.com> writes:

Is there a standard or correct way to initialize @foo_the_stuff in this
example?

This is not the answer, but I have been aware of this issue. I'm
planning to add method combination a la CLOS in the future to support
this issue. It is another option that adding a new hook like
'module_initialize' which is called at instantiation time for all
modules.

              matz.

This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:

http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance

Kind regards

robert

···

2006/5/22, Jeff Rose <rosejn@gmail.com>:

Have a module:

Module Foo
   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)

--
Have a look: Robert K. | Flickr

That's what I was afraid of. In this example case it's no big deal, but in a module where you are accessing a more complex variable many times it's a real pain, let alone inefficient. We are working on an event system, so the hash is a hash of arrays or possibly a hash of hashes. Any of 4 methods could be called, which would require an initialized value. Having this in every method is sorta lame...

   handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]

Of course we can pull it out to a method:

def handlers(key)
   @event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end

  but just initializing on inclusion seems to be the most reasonable way, doesn't it?

-Jeff

Ryan Leavengood wrote:

···

module Foo
  def add_stuff(key, stuff)
    (@foo_the_stuff ||= {})[key] = stuff
  end
end

If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.

Ryan

On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:

Have a module:

Module Foo
   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)

Thanks,
Jeff

Hi --

···

On Tue, 23 May 2006, Jeff Rose wrote:

Well, it took a while but I found the answer. This is done in ActiveRecord to wrap a possible setup method in the unit tests for auto-instrumentation of fixtures. Once I knew what to look for, however, I found an old post by Florian Gross that lays out the exact answer nicely:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834

For educational purposes though, I'll explain a few things I found...

1) The append_features method is deprecated, and the included method is now the preferred callback. This method is called when a module is included, and it is passed the module that has done the including.

2) There is another callback, method_added, which is a meta-class method that is called every time a new method is defined for its class, and the symbol for the method name is passed.

So, the trick is to add a custom method_added method to the meta-class of the class that does the including by extending it in the included callback. The custom method_added needs to redefine initialize after it is added so that it does the custom setup, then calls the original.

Phew... Too bad we can't just have another callback that lets us do this easily. Maybe that feels too much like multiple inheritance or something?

module Foo
def module_initialize
   @myvar = Hash.new {|k,v| k[v] = }
end

def bar(key)
   @mybar[key]
end
end

Isn't this a common thing to want?

I'm probably being thick but what's wrong with just writing a method
that wraps @myvar and initializes it if necessary, and then returns
it?

David

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
   > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
   > Ruby for Rails

and precisely one of the reasons i wrote traits - with traits you can simply
ignore the issue altogether:

   harp:~ > gem install traits

   harp:~ > cat a.rb
   require 'rubygems'
   require 'traits'

   module Foo
     trait 'myvar' => Hash.new{|k,v| k[v] = }
     def bar(key) myvar[key] end
   end

   class Bar
     include Foo
   end

   b = Bar.new

   p b.bar(:k)

   p b.myvar

   harp:~ > ruby a.rb
   
   {:k=>}

:wink:

-a

···

On Tue, 23 May 2006, Jeff Rose wrote:

Well, it took a while but I found the answer. This is done in ActiveRecord to wrap a possible setup method in the unit tests for auto-instrumentation of fixtures. Once I knew what to look for, however, I found an old post by Florian Gross that lays out the exact answer nicely:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834

For educational purposes though, I'll explain a few things I found...

1) The append_features method is deprecated, and the included method is now the preferred callback. This method is called when a module is included, and it is passed the module that has done the including.

2) There is another callback, method_added, which is a meta-class method that is called every time a new method is defined for its class, and the symbol for the method name is passed.

So, the trick is to add a custom method_added method to the meta-class of the class that does the including by extending it in the included callback. The custom method_added needs to redefine initialize after it is added so that it does the custom setup, then calls the original.

Phew... Too bad we can't just have another callback that lets us do this easily. Maybe that feels too much like multiple inheritance or something?

module Foo
def module_initialize
   @myvar = Hash.new {|k,v| k[v] = }
end

def bar(key)
   @mybar[key]
end
end

Isn't this a common thing to want?

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

hi matz-

(rcr ahead)

the other day i realized that one could detect class creation using

   class Class
     def inherited
       ...
     end
   end

but that no such hook existed for class Module. could one be added such as

   class Module
     def instantiated
       ...
     end
   end

to hook into rb_define_module/rb_define_module_under?

regards.

-a

···

On Tue, 23 May 2006, Yukihiro Matsumoto wrote:

Hi,

In message "Re: initializing instance variables in a module" > on Tue, 23 May 2006 00:51:35 +0900, Jeff Rose <rosejn@gmail.com> writes:

>Is there a standard or correct way to initialize @foo_the_stuff in this
>example?

This is not the answer, but I have been aware of this issue. I'm
planning to add method combination a la CLOS in the future to support
this issue. It is another option that adding a new hook like
'module_initialize' which is called at instantiation time for all
modules.

              matz.

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

Yukihiro Matsumoto wrote:

Hi,

>Is there a standard or correct way to initialize @foo_the_stuff in this >example?

This is not the answer, but I have been aware of this issue. I'm
planning to add method combination a la CLOS in the future to support
this issue. It is another option that adding a new hook like
'module_initialize' which is called at instantiation time for all
modules.

              matz.

That would do the trick, and it would probably make the AOP people very happy. But that is a bit different than an explicit module initialization method. Is there a reason you don't want module_initialize or something like that?

CLOS does something like (defmethod rock :before ...), right? Any ideas on how the method combination would work in ruby?

# Maybe using methods...
module Rocker
   def pre_rock
     puts 'pre rock'
   end

   before :rock, :pre_rock
end

# Or with syntax...
module Rocker
   def before:rock
     puts 'pre rock'
   end
end

class Foo
   include Rocker

   def rock
     puts 'We are rocking'
   end
end

Foo.new.rock # => "pre rock\nWe are rocking\n"

-Jeff

···

In message "Re: initializing instance variables in a module" > on Tue, 23 May 2006 00:51:35 +0900, Jeff Rose <rosejn@gmail.com> writes:

Robert Klemme wrote:

This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:

http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance

Nice writeup. I especially like that you captured the need to
tranparently pass arguments thru the module initializer. That's easy to
miss at first glance.

···

--
-- Jim Weirich

--
Posted via http://www.ruby-forum.com/\.

This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:

http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance

Kind regards

robert

This doesn't really solve the problem. The idea is that you don't want the including class to have to do anything related to initialization of the module(s) being included. In your example any including class would have to call super in order to make it work. If Derived implements an initialize method and doesn't call super then the module isn't initialized. But why should it call super, it isn't deriving from anything, it is mixing it in.

The two options Matz mentioned are the way to go. Either a callback (module_initialize), which will act as an initialization method for the module, or the ability for the module to insert its own method(s) before, after, or around the class that includes it. (CLOS method combinations... AOP)

-Jeff

Jeff Rose wrote:

  but just initializing on inclusion seems to be the most reasonable
way, doesn't it?

Put the initialization code in the module's initialize method and have
every class that includes the module call super from its initialize
method:

module Foo
   def initialize(*args, &block)
       # whatever...
   end
end

class Bar
   include Foo
   def initialize(*args, &block)
       super # calls Foo's initialize
       # more stuff
   end
end

···

--
Posted via http://www.ruby-forum.com/\.

Jeff, I tried a few combinations of class_eval and module_eval and I
couldn't figure it out. What seems to be desired is for the mixed-in
module code to create an instance variable in the class which is doing
the mixin. I'll bet there's a way to do it.

···

On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:

That's what I was afraid of. In this example case it's no big deal, but
in a module where you are accessing a more complex variable many times
it's a real pain, let alone inefficient. We are working on an event
system, so the hash is a hash of arrays or possibly a hash of hashes.
Any of 4 methods could be called, which would require an initialized
value. Having this in every method is sorta lame...

   handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]

Of course we can pull it out to a method:

def handlers(key)
   @event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end

  but just initializing on inclusion seems to be the most reasonable
way, doesn't it?

-Jeff

Ryan Leavengood wrote:
> module Foo
> def add_stuff(key, stuff)
> (@foo_the_stuff ||= {})[key] = stuff
> end
> end
>
> If @foo_the_stuff is null, it will be initialized to an empty hash,
> otherwise the existing value will be used. I consider this use of ||=
> to be a Ruby idiom.
>
> Ryan
>
> On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
>> Have a module:
>>
>> Module Foo
>> def add_stuff(key, stuff)
>> @foo_the_stuff[key] = stuff
>> end
>> end
>>
>> class Bar
>> include Foo
>> end
>>
>> Is there a standard or correct way to initialize @foo_the_stuff in this
>> example? Should the add_stuff method check whether the variable has
>> been initialized every time, or should this be done by implementing a
>> callback like append_features or included? (That's how I'd want to do
>> it, but it's not clear which or how...)
>>
>> Thanks,
>> Jeff
>

Hi --

Ryan Leavengood wrote:

Have a module:

Module Foo
   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo
end

Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)

Thanks,
Jeff

module Foo
  def add_stuff(key, stuff)
    (@foo_the_stuff ||= {})[key] = stuff
  end
end

If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.

Ryan

That's what I was afraid of. In this example case it's no big deal, but in a module where you are accessing a more complex variable many times it's a real pain, let alone inefficient. We are working on an event system, so the hash is a hash of arrays or possibly a hash of hashes. Any of 4 methods could be called, which would require an initialized value. Having this in every method is sorta lame...

handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]

Of course we can pull it out to a method:

def handlers(key)
@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end

but just initializing on inclusion seems to be the most reasonable way, doesn't it?

Not if it leads to code you strongly dislike :slight_smile: It seems OK to wrap
it in a method, perhaps like this:

   def event_handlers
     @event_handlers ||= Hash.new {|k,v| k[v] = }
   end

   def whatever ...
     handlers = event_handlers[key]
   end

David

···

On Tue, 23 May 2006, Jeff Rose wrote:

On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
   > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
   > Ruby for Rails

You still have to call it every time you use the variable.

···

On 5/22/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

Hi --

On Tue, 23 May 2006, Jeff Rose wrote:

> Well, it took a while but I found the answer. This is done in ActiveRecord
> to wrap a possible setup method in the unit tests for auto-instrumentation of
> fixtures. Once I knew what to look for, however, I found an old post by
> Florian Gross that lays out the exact answer nicely:
>
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834
>
> For educational purposes though, I'll explain a few things I found...
>
> 1) The append_features method is deprecated, and the included method is now
> the preferred callback. This method is called when a module is included, and
> it is passed the module that has done the including.
>
> 2) There is another callback, method_added, which is a meta-class method that
> is called every time a new method is defined for its class, and the symbol
> for the method name is passed.
>
> So, the trick is to add a custom method_added method to the meta-class of the
> class that does the including by extending it in the included callback. The
> custom method_added needs to redefine initialize after it is added so that it
> does the custom setup, then calls the original.
>
> Phew... Too bad we can't just have another callback that lets us do this
> easily. Maybe that feels too much like multiple inheritance or something?
>
> module Foo
> def module_initialize
> @myvar = Hash.new {|k,v| k[v] = }
> end
>
> def bar(key)
> @mybar[key]
> end
> end
>
> Isn't this a common thing to want?

I'm probably being thick but what's wrong with just writing a method
that wraps @myvar and initializes it if necessary, and then returns
it?

David

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
   > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
   > Ruby for Rails

Hi,

In message "Re: [OT] Re: initializing instance variables in a module"

the other day i realized that one could detect class creation using

  class Class
    def inherited
      ...
    end
  end

but that no such hook existed for class Module. could one be added such as

  class Module
    def instantiated
      ...
    end
  end

to hook into rb_define_module/rb_define_module_under?

I am not sure what situation that kind of method is useful. But in
any case I don't feel the word "instantiated" is the right word for
the method. Note that I am not opposing the method itself.

              matz.

> This thread seems to have gone astray a bit but I didn't see this
> solution which I regard the standard way to handle this. The important
> part is to use initialize(*a,&b) in the module. I've put this on the
> wiki for easier reference:
>
> http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance
>
> Kind regards
>
> robert

This doesn't really solve the problem. The idea is that you don't want
the including class to have to do anything related to initialization of
the module(s) being included.

It doesn't have to.

In your example any including class would
have to call super in order to make it work.

But this is true for classes inheriting anyway. You could even make it
yourself a habit to even call super if you do not inherit specifically
(i.e. inherit Obect).

If Derived implements an
initialize method and doesn't call super then the module isn't
initialized. But why should it call super, it isn't deriving from
anything, it is mixing it in.

I don't fully agree: Derived actually inherits from Base so it's
standard procedure to invoke the super class initialize. If you then
write your module initialize with signature (*a,&b) you can insert it
into *any* inheritance chain that obeys the basic behavior without
doing any harm or losing initialization code.

The two options Matz mentioned are the way to go. Either a callback
(module_initialize), which will act as an initialization method for the
module, or the ability for the module to insert its own method(s)
before, after, or around the class that includes it. (CLOS method
combinations... AOP)

Well, yes, if a change to the language / lib can be considered these
are probably better.

Kind regards

robert

···

2006/5/23, Jeff Rose <rosejn@gmail.com>:

--
Have a look: http://www.flickr.com/photos/fussel-foto/

Francis Cianfrocca schrieb:

You still have to call it every time you use the variable.

Do you realy need to use the variable directly?
My scripts tend to have very little use of '@'.

module Foo
def bar(key)
   @myvar ||= Hash.new {|k,v| k[v] = }
   @myvar[key]
end
end

class Test
  include Foo
end

t = Test.new
t.bar('baz') << 'eeek'
p t.bar('baz')

I didn't followed the whole thread so please ignore me
if this was suggested before.

cheers

Simon

Hi,

Jeff Rose wrote:

  but just initializing on inclusion seems to be the most reasonable
way, doesn't it?

Put the initialization code in the module's initialize method and have
every class that includes the module call super from its initialize
method:

module Foo
   def initialize(*args, &block)
       # whatever...
   end
end

class Bar
   include Foo
   def initialize(*args, &block)
       super # calls Foo's initialize
       # more stuff
   end
end

What is wrong with what Tim suggests? I must be missing something. Here is a specific example:

module Foo
   def initialize
     super
     @foo_the_stuff = {}
   end

   def add_stuff(key, stuff)
     @foo_the_stuff[key] = stuff
   end
end

class Bar
   include Foo

   def show_stuff
     puts "stuff: #{@foo_the_stuff.inspect}"
   end
end

b1 = Bar.new
b2 = Bar.new
b1.add_stuff("one", 1)
b2.add_stuff("two", 2)
b1.add_stuff("three", 3)
b2.add_stuff("four", 4)

b1.show_stuff
b2.show_stuff

Cheers,
Bob

···

On May 22, 2006, at 12:20 PM, Tim Hunter wrote:

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;