'Initializing' modules

G

George Moschovitis

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
 
R

Robert Klemme

George Moschovitis said:
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
 
G

George Moschovitis

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

George Moschovitis
www.navel.gr
 
A

Ara.T.Howard

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

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

ts

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

Same than

ret = super

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

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


Guy Decoux
 
J

Joel VanderWerf

ts said:
A> def method(*args, &block)
A> 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
 
E

Elias Athanasopoulos

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

Robert Klemme

Elias Athanasopoulos said:
Hello!



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
 
E

Elias Athanasopoulos

Hello!

Elias Athanasopoulos said:
Hello!



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. :)

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

Regards,
 
T

ts

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

before trying to fix it, look the source :)

E> special reason to Matz' brain about this behaviour.


Guy Decoux
 
E

Elias Athanasopoulos

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

before trying to fix it, look the source :)

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

Regards,
 
T

ts

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

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

:)



Guy Decoux
 
E

Elias Athanasopoulos

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

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

:)

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

Regards,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,214
Latest member
JFrancisDavis

Latest Threads

Top