Jokester
Jokester

Reputation: 5617

Behavior and purpose of class redefinition code in another class

Have been observing some unexpected behavior when a class region appears in another class definition:

Such region overrides whole class definition there.

However, the same code will just add new method to this class, as shown in codes below.

Why is Ruby designed like this, if it isn't a little beyond intuition?

require 'pp'

def pp_methods obj
  pp obj.methods - nil.methods
end

#first definition of A
class A
  def method1
  end
end

#add method3 to A
class A
  def method3
  end
end

class B
  #class A got overridden within class B
  class A
    def method2
    end
  end
  def initialize
    a=A.new
    pp_methods a  # => [:method2]
  end
end

a1=A.new
pp_methods a1     # => [:method1,:method3]

b=B.new

a2=A.new
pp_methods a1     # => [:method1,:method3]


pp_methods a2     # => [:method1,:method3] 

Upvotes: 0

Views: 42

Answers (1)

Andrew Marshall
Andrew Marshall

Reputation: 96934

Being able to "reopen" classes is actually very useful. By having this ability we can easily add functionality to existing libraries, or fix issues ("monkey-patch"), without having to modify the actual library code. A contrived example:

class String
  def foo
    "bar!"
  end
end

"hello".foo # => "bar!"

As for the second case, that A is actually B::A, which is entirely different than A, and thus not reopening your initial A. We can see this here:

class A
end

A # => A

class B
end

B    # => B
B::A # warning: toplevel constant A referenced by B::A
     # => A

class B
  class A
  end
end

B::A           # => B::A
A.object_id    # => 70359576062780
B::A.object_id # => 70359575976320

Upvotes: 3

Related Questions