Redefine modules?

Hi,
I am quite new to Ruby and make some experiences with modules and
classes.
I have defined a module and an inner class with the same name (Cucc) and
a static method (x) for the class. Then I made a redefinition (or
whatever you call) of the same module (Cucc) without the inner class but
with a static (x) method.

Before the redefinition x method of the Cucc module’s inner class Cucc
is called but right after the modules static method is called. Why?

I totally agree that coding style like below is among the first 10 on
the list to avoid during programming, but though I want to understand
the behavior!

I have created the following code:
------CODE START-----------
module Cucc
def Cucc.x(arg)
puts arg.to_s + " Cucc.x"
end
def x(arg)
puts arg.to_s + " Cucc module x"
end
class Cucc
def Cucc.x(arg)
puts arg.to_s + " Cucc module Cucc class Cucc.x"
end
def x(arg)
puts arg.to_s + " Cucc module Cucc class x"
end
end
end

puts “Cucc class started first”
Cucc::x(10)
c = Cucc::Cucc.new
c.x(20)
Cucc::Cucc.x(30)
puts “Cucc class ended first”

module Cucc
def Cucc.x(arg)
puts arg.to_s + " Redefined Cucc module Cucc.x"
end
def x(arg)
puts arg.to_s + " Redefined Cucc module x"
end
end

puts “Cucc class started second”
Cucc::x(10)
c = Cucc::Cucc.new
c.x(20)
Cucc::Cucc.x(30)
puts “Cucc class ended second”
------CODE END-----------

The outcome is the following:
Cucc class started first
10 Cucc.x
20 Cucc module Cucc class x
30 Cucc module Cucc class Cucc.x
Cucc class ended first
Cucc class started second
10 Cucc.x
20 Cucc module Cucc class x
30 Redefined Cucc module Cucc.x
Cucc class ended second

How the hell is it possible that for the “30” that I get different
result when having a redefinition (or so) of the Cucc module?

At first the inner class’ static method is called and in the second case
the static method of the module!

Thanks in advanced, --stan–

2009/2/11 Stanley R. [email protected]:

I am quite new to Ruby and make some experiences with modules and
classes. (…)

Stan, maybe the following code will give you some hints:

module Cucc
puts Cucc.class # => Module
class Cucc; end
puts Cucc.class # => Class
end

It has to do with the way Ruby resolves the names of constants.

Regards,
Pit

Pit C. wrote:

2009/2/11 Stanley R. [email protected]:

I am quite new to Ruby and make some experiences with modules and
classes. (…)

Stan, maybe the following code will give you some hints:

module Cucc
puts Cucc.class # => Module
class Cucc; end
puts Cucc.class # => Class
end

It has to do with the way Ruby resolves the names of constants.

Regards,
Pit

Hi Pit,
it’s OK, but I still don’t understand what is the situation when
overriding a module.

I have added the class method to check what happens:
Cucc::Cucc.x(30) # => 30 Cucc module Cucc class Cucc.x
puts Cucc::Cucc # => Class

But after the redefinition of the same module (without having the Cucc
innerclass) the same lines lead to different outcome:
Cucc::Cucc.x(30) # => 30 Redefined Cucc module Cucc.x
puts Cucc::Cucc # => Class

Can you please explain me this?

Thanks in advance --stan–

On Thu, Feb 12, 2009 at 8:11 AM, Stanley R. <
[email protected]> wrote:

puts Cucc.class  # => Class

I have added the class method to check what happens:
Cucc::Cucc.x(30) # => 30 Cucc module Cucc class Cucc.x
puts Cucc::Cucc # => Class

But after the redefinition of the same module (without having the Cucc
innerclass) the same lines lead to different outcome:
Cucc::Cucc.x(30) # => 30 Redefined Cucc module Cucc.x
puts Cucc::Cucc # => Class

Can you please explain me this?

You’ve got two or three misconceptions here.

First, you seem to assume that redefining a method won’t lead to a
different
outcome. Why else would you redefine a method? In ruby redefining a
method
replaces that method, so you’ll get the new version when you invoke it.
So
the real question is why aren’t you seeing the OTHER redefinition, which
is
the second misconception.

Second, in your test code you are never calling the second x method.
This
method will only be accessible in an instance of a class which includes
the
Cucc module. So you might want to add

class Test
include Cucc
end

test = Test.new
before your “started first”

and then add test.x(40) to each of your sets of calls, this should show
that
when you call it you do get the redefined method.

Now, what might seem strange is that you might think that it should be
the
Cucc::x(10)

which invokes the other redefined method, after all first you wrote:

module Cucc
def Cucc.x(…
end

and wrote the same thing in the redefinition, this is the third
misconception, that the meaning of Cucc WITHIN the module means the same
thing in both cases, it doesn’t.

I’m not sure whether or not you are really confused about this is
because of
the string produced in the overriden method. I’m not sure whether you
are
documenting your intention or your surprise with the result.

The way Ruby resolves ‘global’ names is that it starts looking for the
name
in the current module, and if it doesn’t find it, it looks for the same
name
in the enclosing name scope.

So in this case, it will first look for ::Cucc::Cucc (where the initial
::
indicates the outermost name scope), then it will look for ::Cucc

The first time, before what you are calling the inner class (which by
the
way is a Java concept not directly transferrable to Ruby) doesn’t exist,
so
it doesn’t find ::Cucc::Cucc and you end up defining a singleton method
of
the Cucc module.

The second time, it does find ::Cucc::Cucc so you end up redefining the
instance method x in Cucc::Cucc.

If you really wanted to redefine the ::Cucc#x you should right the
redefinition as either:

module Cucc
def self.x(arg)
puts arg.to_s + " Redefined Cucc module.x"
end
#…
end

or outside of the module reopening

def Cucc.x(arg)
puts arg.to_s + " Redefined Cucc module.x"
end

HTH


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale

2009/2/12 Rick DeNatale [email protected]:

(…)
and wrote the same thing in the redefinition, this is the third
misconception, that the meaning of Cucc WITHIN the module means the same
thing in both cases, it doesn’t.
(…)

Thanks Rick for the detailed explanation. As you know I’ve been too
involved in some other threads lately :slight_smile:

Regards,
Pit