'Initializing' modules

Hello everyone,

I am looking for an elegant solution to a common problem.
Lets say I have 2 modules (A, B):

module A
  attr_accessor :val1
  attr_accessor :val2

  def initialize
    @val1 = @val2 = "A"
  end
end

module B
  attr_accessor :val3
  attr_accessor :val4

  def initialize
    @val3 = @val4 = "B"
  end
end

I include the modules in a news class:

class MyClass
  include A, B

  def initialize
    # ???
  end
end

Is there a way to automatically call the initialization code for the two modules ? Is there a ruby idiom for this?

Thanks in advance for any help!

George Moschovitis
Navel

"George Moschovitis" <gm@navel.gr> schrieb im Newsbeitrag
news:cd345h$sdg$1@ulysses.noc.ntua.gr...

Hello everyone,

I am looking for an elegant solution to a common problem.
Lets say I have 2 modules (A, B):

module A
attr_accessor :val1
attr_accessor :val2

def initialize
@val1 = @val2 = "A"
end
end

module B
attr_accessor :val3
attr_accessor :val4

def initialize
@val3 = @val4 = "B"
end
end

I include the modules in a news class:

class MyClass
include A, B

def initialize
# ???
end
end

Is there a way to automatically call the initialization code for the two
modules ? Is there a ruby idiom for this?

Thanks in advance for any help!

The Ruby idiom is to use 'super' all over the place:

module A
  attr_accessor :val1
  attr_accessor :val2

  def initialize(*args)
    super
    @val1 = @val2 = "A"
  end
end

module B
  attr_accessor :val3
  attr_accessor :val4

  def initialize(*args)
    super
    @val3 = @val4 = "B"
  end
end

class MyClass
  include A, B

  def initialize
    super
    @foo = "bar"
  end
end

=>

irb(main):028:0> MyClass.new
=> #<MyClass:0x10187e08 @val3="B", @val2="A", @foo="bar", @val1="A",
@val4="B">

Note: to make this work seamless it's best to define initialize(*args) in
a module because otherwise there will be problems if you include a module
in different classes whose different base classes accept a different
amount of arguments.

You might want to experiment with the attached script a bit.

Regards

    robert

mod-init.rb (908 Bytes)

if i understand what you are trying to do correctly, you simply need to call
'super' in the appropriate places:

   ~ > cat a.rb
   module M
     def initialize
       super
       p 42
     end
   end
   module M2
     def initialize
       super
       p 42.0
     end
   end
   class C
     include M
     include M2
     def initialize
       super
       p 'forty-two'
     end
   end

   C.new

   ~ > ruby a.rb
   42
   42.0
   "forty-two"

initialize is simply a method so the inclusion of a module which defines it
will cause the currently defined initialize (if there is one) to be
overridden. so after the 'include M' statement there is one initialize
defined, after the 'include M2' a new one is defined, and finally class C
defines it's own. if the initialize methods themselves are written in such a
way that they call any previously defined method of the same name (typically
with the same arguments) then they will all effectively be chained together.
in general the pattern for this is:

   def method(*args, &block)

     ret = super(*args, &block)

     # whatever you want to do

     ret

   end

in otherwords, when calling super be sure to pass along any required args and
block and, if you want your new object plug-in where it's superclass would, be
sure to return the expected type(s).

cheers.

-a

···

On Wed, 14 Jul 2004, George Moschovitis wrote:

Hello everyone,

I am looking for an elegant solution to a common problem.
Lets say I have 2 modules (A, B):

module A
  attr_accessor :val1
  attr_accessor :val2

  def initialize
    @val1 = @val2 = "A"
  end
end

module B
  attr_accessor :val3
  attr_accessor :val4

  def initialize
    @val3 = @val4 = "B"
  end
end

I include the modules in a news class:

class MyClass
  include A, B

  def initialize
    # ???
  end
end

Is there a way to automatically call the initialization code for the two modules ? Is there a ruby idiom for this?

Thanks in advance for any help!

George Moschovitis
Navel

--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
A flower falls, even though we love it;
and a weed grows, even though we do not love it. --Dogen

===============================================================================

Hello Robbert

The Ruby idiom is to use 'super' all over the place:
...
You might want to experiment with the attached script a bit.

this seems to work, thank you very much!
I am wondering if there are any side-effects though (ie excessive calling of super).

Another surpising thing:

include A, B seems to include the Modules in the reverse order
include A; include B works as expected.

What about the Principle of Least Surprise :slight_smile:

George Moschovitis
www.navel.gr

   def method(*args, &block)
     ret = super(*args, &block)

  Same than

        ret = super

in otherwords, when calling super be sure to pass along any required args and
block and, if you want your new object plug-in where it's superclass would, be
sure to return the expected type(s).

and the last initialize, i.e. Object#initialize, take zero argument :slight_smile:

Guy Decoux

ts wrote:

"A" == Ara T Howard <ahoward@noaa.gov> writes:

> def method(*args, &block)
> ret = super(*args, &block)

  Same than

        ret = super

And note that

   ret = super()

is different from

   ret = super

The first one passes no arguments. The second one passes the original arguments. In other words, you can explicitly specify the argument list by using parens.

But be careful: if the method was called with a block, it will be passed to the superclass in both cases. For example:

class A
   def initialize
     yield 3 if block_given?
   end
end

class B < A
   def initialize
     super()
   end
end

B.new {|x| p x} # ==> 3

One way to explicitly prevent the block from being passed is:

class B < A
   def initialize
     super(&nil) # or: super() {}
   end
end

Hello!

Another surpising thing:

include A, B seems to include the Modules in the reverse order
include A; include B works as expected.

Since nobody replied and I think it's an interesting question,
does anyone know why this happens?

elathan@velka:~> cat gm.rb
module A
  attr_accessor :val1
  attr_accessor :val2

  def initialize
    @val1 = @val2 = "A"
  end
end

module B
  attr_accessor :val3
  attr_accessor :val4

  def initialize
    @val3 = @val4 = "B"
  end
end

class MyClass
  include A, B
  def initialize
      super
  end
end

class MyClass2
    include A
    include B
    def initialize
        super
    end
end

p MyClass.new
p MyClass2.new

elathan@velka:~> ruby gm.rb
#<MyClass:0x401cc1c4 @val2="A", @val1="A">
#<MyClass2:0x401cc0e8 @val4="B", @val3="B">
elathan@velka:~> ruby -v
ruby 1.9.0 (2004-05-25) [i686-linux]

Regards,

···

On Wed, Jul 14, 2004 at 09:02:21PM +0900, George Moschovitis wrote:
--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

"Elias Athanasopoulos" <elathan@phys.uoa.gr> schrieb im Newsbeitrag
news:20040714024430.GA810@velka.phys.uoa.gr...

Hello!

> Another surpising thing:
>
> include A, B seems to include the Modules in the reverse order
> include A; include B works as expected.

Since nobody replied and I think it's an interesting question,
does anyone know why this happens?

I guess the reason is that in the first case [A,B] is inserted into the
sequence of ancestors as is, while in the second case first A is inserted
and then B, which effectively yields [derived, B, A, base, ...] as
ancestors.

    robert

···

On Wed, Jul 14, 2004 at 09:02:21PM +0900, George Moschovitis wrote:

Hello!

"Elias Athanasopoulos" <elathan@phys.uoa.gr> schrieb im Newsbeitrag
news:20040714024430.GA810@velka.phys.uoa.gr...
> Hello!
>
> > Another surpising thing:
> >
> > include A, B seems to include the Modules in the reverse order
> > include A; include B works as expected.
>
> Since nobody replied and I think it's an interesting question,
> does anyone know why this happens?

I guess the reason is that in the first case [A,B] is inserted into the
sequence of ancestors as is, while in the second case first A is inserted
and then B, which effectively yields [derived, B, A, base, ...] as
ancestors.

You maybe right. But, IMHO, this is a real coding style
enforcement. I mean, it's difficult to distinguish that
'import A, B' is different than 'import A; import B'.

It's a kind of surprising. :slight_smile:

I am willing to help to fix it *if* there is not a
special reason to Matz' brain about this behaviour.

Regards,

···

On Thu, Jul 15, 2004 at 08:37:17PM +0900, Robert Klemme wrote:

> On Wed, Jul 14, 2004 at 09:02:21PM +0900, George Moschovitis wrote:

--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

I am willing to help to fix it *if* there is not a

before trying to fix it, look the source :slight_smile:

special reason to Matz' brain about this behaviour.

Guy Decoux

I guess it is difficult to fix. Maybe it can break the
grammar parser in various places?

Regards,

···

On Fri, Jul 16, 2004 at 02:13:03AM +0900, ts wrote:

> I am willing to help to fix it *if* there is not a

before trying to fix it, look the source :slight_smile:

--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

I guess it is difficult to fix. Maybe it can break the
grammar parser in various places?

Read rb_mod_include() in eval.c, and see how ruby make the loop `while'

:slight_smile:

Guy Decoux

Ok, got it. I'll try to submit a patch to the documentation
to illustrate the different behaviour. :slight_smile:

Regards,

···

On Fri, Jul 16, 2004 at 02:22:43AM +0900, ts wrote:

> I guess it is difficult to fix. Maybe it can break the
> grammar parser in various places?

Read rb_mod_include() in eval.c, and see how ruby make the loop `while'

:slight_smile:

--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky