To be a Module, or not to be

Hello folks,

I am attempting to write a transparent persistence framework and am having a
hard time deciding if something should be a class or it should be a module.
The reason I would like it to be a module is because I am trying to write a
framework where I do not want to interfere with the object model used by
clients of the framework. Ideally they would just include my module and get
my functionality for free thus making persistence even more transparent.

Where I get confused is that this module needs to set some instance variable
state and initialize those variables. I would like it if there was a way for
the state to be set after the the client object has been initialized? If that
is not possible, or possibly not the best way to do it then please let me
know.

Here is some code:

···

Encapsulates the behavior needed to make objects persistent and is the

module

all classes wishing to be persisted should mix this in.

module ROS
module Persistable

def initialize
# I want these variables to be instance vars.
@is_persistent = false
@timestamp = null
end

def retrieve

end

def save

end

def delete

end

end
end

Many thanks in advance for any help offered.


Signed,
Holden Glova

module ROS
module Persistable

It really depend on what you want to do

pigeon% cat b.rb
#!/usr/bin/ruby
module ROS
   module Persistable

      def initialize
         # I want these variables to be instance vars.
         @is_persistent = false
         @timestamp = nil
      end
   end
end

class A
   include ROS::Persistable

   def initialize
      @a = 12
      super
   end
end

p A.new
pigeon%

pigeon% b.rb
#<A:0x401b09a0 @is_persistent=false, @a=12, @timestamp=nil>
pigeon%

Guy Decoux

Thank you for the quick response Guy! Although I’m not sure how the initialize
method in the Module is called. I see you make a call to super there, but I
was not aware that a super call would call methods in a Module! The behavior
is exactly what was desired though. Must I call super from the class to get
the Modules initialize method called?


Signed,
Holden Glova

···

On Sun, 11 Aug 2002 21:25, ts wrote:

module ROS
module Persistable

It really depend on what you want to do

pigeon% cat b.rb
#!/usr/bin/ruby
module ROS
module Persistable

  def initialize
     # I want these variables to be instance vars.
     @is_persistent = false
     @timestamp     = nil
  end

end
end

class A
include ROS::Persistable

def initialize
@a = 12
super
end
end

p A.new
pigeon%

pigeon% b.rb
#<A:0x401b09a0 @is_persistent=false, @a=12, @timestamp=nil>
pigeon%

Guy Decoux

is exactly what was desired though. Must I call super from the class to get
the Modules initialize method called?

Yes,

When you write

  class A

The inheritance is A ==> Object ==> [Kernel]

When you add

     include ROS::Persistence

the inheritance is A ==> [ROS::Persistence] ==> Object ==> [Kernel]

ruby has inserted a proxy class [ROS::Persistence] before A

In A#initialize when you call #super, ruby find the method
ROS::Persistence#initialize

Guy Decoux

i did not realize this either. what happens if you include more then one
module?

~transami

···

On Sun, 2002-08-11 at 03:40, ts wrote:

When you add

 include ROS::Persistence

the inheritance is A ==> [ROS::Persistence] ==> Object ==> [Kernel]

ruby has inserted a proxy class [ROS::Persistence] before A

In A#initialize when you call #super, ruby find the method
ROS::Persistence#initialize

Thank you for the solution and the explanation :slight_smile:


Signed,
Holden Glova

···

On Sun, 11 Aug 2002 21:40, ts wrote:

is exactly what was desired though. Must I call super from the class to
get H> the Modules initialize method called?

Yes,

When you write

class A

The inheritance is A ==> Object ==> [Kernel]

When you add

 include ROS::Persistence

the inheritance is A ==> [ROS::Persistence] ==> Object ==> [Kernel]

ruby has inserted a proxy class [ROS::Persistence] before A

In A#initialize when you call #super, ruby find the method
ROS::Persistence#initialize

Guy Decoux

Beware of this, though:

module M 
  def initialize
    puts "M"
  end
end

class A
  def initialize
    puts "A"  
  end
end

class B < A
  include M
  def initialize
    puts "B"
    super
  end
end

b = B.new
B
M

A#initialize doesn’t get invoked. To ensure this, we must
call #super from M#initialize:

module M 
  def initialize
    puts "M"
    super
  end
end

b = B.new
B
M
A

Of course, observe the order in which they get invoked, though.

And, requiring #initialize to invoke #super means that mixing
the module in with something like the String class becomes
tricky.

– Dossy

···

On 2002.08.11, ts decoux@moulon.inra.fr wrote:

ruby has inserted a proxy class [ROS::Persistence] before A

In A#initialize when you call #super, ruby find the method
ROS::Persistence#initialize


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

i did not realize this either. what happens if you include more then one
module?

It do the same, for example

   class A # A ==> Object ==> [Kernel]
      include B # A ==> [B] ==> Object ==> [Kernel]
      include C # A ==> [C] ==> [B] ==> Object ==> [Kernel]
      include B # A ==> [C] ==> [B] ==> Object ==> [Kernel]
                   # not modified because it has found the proxy class [B]

Now with

   module C end
   module B
      include C
   end
   class A
      include B # A ==> [B] ==> [C] ==> Object ==> [Kernel]
   end

Guy Decoux

Ok, with this nice illustration of how it works, I should definately call
super from the intialize method i have in the module, no?


Signed,
Holden Glova

···

On Sun, 11 Aug 2002 21:50, ts wrote:

i did not realize this either. what happens if you include more then one
module?

It do the same, for example

class A # A ==> Object ==> [Kernel]
include B # A ==> [B] ==> Object ==> [Kernel]
include C # A ==> [C] ==> [B] ==> Object ==> [Kernel]
include B # A ==> [C] ==> [B] ==> Object ==> [Kernel]
# not modified because it has found the proxy class [B]

Now with

module C end
module B
include C
end
class A
include B # A ==> [B] ==> [C] ==> Object ==> [Kernel]
end

Guy Decoux

Ok, with this nice illustration of how it works, I should definately call
super from the intialize method i have in the module, no?

no, with

  module B
     def initialize
        super
     end
  end

  class A
     include B
  end

  A.new

ruby call B#initialize but the #super in B#initialize will search
#initialize in Object, then Kernel

  with

  class A
     include B

     def initialize
     # without super
     end
  end

ruby call only A#initialize

Guy Decoux

Ok, with this nice illustration of how it works, I should definately
call H> super from the intialize method i have in the module, no?

no, with

module B
def initialize
super
end
end

class A
include B
end

A.new

ruby call B#initialize but the #super in B#initialize will search
#initialize in Object, then Kernel

I don’t see how that is a bad thing?

with

class A
include B

 def initialize
 # without super
 end

end

ruby call only A#initialize

Guy Decoux

Reason why I suggested adding super in the Module was because if the client
chooses to do something similar with other modules then by my Module not
calling super would mean that the other Module#initialize methods defined in
their modules would not be called - is that correct?


Signed,
Holden Glova

···

On Sun, 11 Aug 2002 22:13, ts wrote:

I don't see how that is a bad thing?

pigeon% ruby
module B
   def initialize(a)
      p "B"
      super
   end
end

class A
   include B
end

A.new(12)
^D
"B"
-:4:in `initialize': wrong # of arguments(1 for 0) (ArgumentError)
        from -:4:in `initialize'
        from -:12:in `new'
        from -:12
pigeon%

Reason why I suggested adding super in the Module was because if the client
chooses to do something similar with other modules then by my Module not
calling super would mean that the other Module#initialize methods defined in
their modules would not be called - is that correct?

it depend on what you want to do :-)))

Guy Decoux