Forum: Ruby Redefine modules?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
1f0fd908033de194d6e1af62b3d1b33a?d=identicon&s=25 Stanley Roberts (--stan--)
on 2009-02-11 11:48
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--
50b2daf0e7666574579b9edaf8f2b69a?d=identicon&s=25 Pit Capitain (Guest)
on 2009-02-11 14:03
(Received via mailing list)
2009/2/11 Stanley Roberts <caseyandstanley@hotmail.com>:
>   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
1f0fd908033de194d6e1af62b3d1b33a?d=identicon&s=25 Stanley Roberts (--stan--)
on 2009-02-12 14:12
Pit Capitain wrote:
> 2009/2/11 Stanley Roberts <caseyandstanley@hotmail.com>:
>>   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--
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2009-02-12 17:36
(Received via mailing list)
On Thu, Feb 12, 2009 at 8:11 AM, Stanley Roberts <
caseyandstanley@hotmail.com> 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
50b2daf0e7666574579b9edaf8f2b69a?d=identicon&s=25 Pit Capitain (Guest)
on 2009-02-12 20:02
(Received via mailing list)
2009/2/12 Rick DeNatale <rick.denatale@gmail.com>:
> (...)
> 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 :-)

Regards,
Pit
This topic is locked and can not be replied to.