ruby self.class.class_eval or singleton_class.class_eval

3.4k Views Asked by At

What is difference when I do

class T

  def initialize
   self.class.class_eval do
      def test
        return self.class.object_id
     end
   end
  end

end

and

class T

  def initialize
    singleton_class.class_eval do
      def test
        return self.class.object_id
     end
   end
  end

end

Thanks

PS. Tass answered that in this example , singleton_class will return a different object_id for each new object, because a singleton_class belongs to one Object only. But IRB shows next

1.9.2p180 :001 > class T
1.9.2p180 :002?>   
1.9.2p180 :003 >     def initialize
1.9.2p180 :004?>      singleton_class.class_eval do
1.9.2p180 :005 >               def test
1.9.2p180 :006?>                 return self.class.object_id
1.9.2p180 :007?>              end
1.9.2p180 :008?>        end
1.9.2p180 :009?>     end
1.9.2p180 :010?>   
1.9.2p180 :011 >     end
 => nil 
1.9.2p180 :012 > t = T.new
 => #<T:0x00000100ae9cb8> 
1.9.2p180 :013 > t1 = T.new
 => #<T:0x00000100ad7ef0> 
1.9.2p180 :014 > t1.test == t.test
 => true 
1.9.2p180 :015 > t1.test
 => 2153233300 
1.9.2p180 :016 > t.test
 => 2153233300 
1.9.2p180 :017 > 
2

There are 2 best solutions below

2
On BEST ANSWER

The difference between instances of these T classes is in the method lookup algorithm: method is always searched in the singleton class (and its modules) and only if it is not found here, it is searched in the class.

This mean if we add method test to the first implementation of class T after initialization we will get different result than when we do the same for second implementation of class T:

# First example
class T
  def initialize
    self.class.class_eval do
      def test
        return self.class.object_id
      end
    end
  end
end

t = T.new

class T
  def test
    'overriden'
  end
end

puts t.test # => 'overriden'

class T
  def initialize
    singleton_class.class_eval do
      def test
        return self.class.object_id
      end
    end
  end
end

t = T.new

class T
  def test
    'overriden'
  end
end

puts t.test # => 77697390
3
On

singleton_class gives you the Class that is unique to that object. self.class gives you the class that all objects of that Class share. Example

foobar = Array.new

# this defines a method on the singleton class
def foobar.size
  "Hello World!"
end

foobar.size  # => "Hello World!"
foobar.class # => Array

bizbat = Array.new
bizbat.size  # => 0

In the example above, singleton_class will return a different object_id for each new object, because a singleton_class belongs to one Object only. self.class will return the same because self.class does point to the same Class every time.