Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ruby create 3 objects after a class is created?

I was studying about Ruby's metaclass. I read this answer where it is nicely described what metaclass is. It's showed there when a class is created it will create two objects. Which is understandable. One for the class itself and one for it's metaclass. But when I am trying it myself I see that it is creating three objects.

puts "Before Class Creation object count - #{ObjectSpace.count_objects[:T_CLASS]}"
class Test
  def self.foo # test_singleton
    p 'Printed from method #foo'
  end

  def bar # test
    p 'Printed from method #bar'
  end
end
puts "After Class Creation object count - #{ObjectSpace.count_objects[:T_CLASS]}"

###############

Before Class Creation object count - 949
After Class Creation object count - 952

I am using Ruby - 2.5.1.

Can anyone help me understand this one?

Update:

The reference SO post that I added is using ruby-1.9.1 or greater, as the method count_objects for ObjectSpace was introduced in 1.9.1. It seems that the T_CLASS count has always always been 3 (tried with ruby-1.9.3-p551).

So, till now it's still a mystery why this answer. Ruby under a microscope also says the count is 2.

like image 683
Rafayet Monon Avatar asked Apr 04 '20 17:04

Rafayet Monon


People also ask

What is the difference between a class and an object in Ruby?

An object is a unit of data. A class is what kind of data it is.

What do you mean by objects in Ruby?

Everything in Ruby is an object. All objects have an identity; they can also hold state and manifest behaviour by responding to messages. These messages are normally dispatched through method calls. A string is an example of a Ruby object.

What is meant by object creation in Ruby extension?

It is called whenever a new object is created. Whenever new class method called it always call initialize instance method. initialize method is like a constructor, whenever new objects are created initialize method called.


1 Answers

From https://bugs.ruby-lang.org/issues/16788:

Creating a class automatically creates a singleton class (which is not accessible to the user). Referencing the singleton class of a class automatically creates a singleton class of that singleton class. This is to keep consistency of the inheritance structure of metaclasses. Otherwise, class methods wouldn't inherit from the superclass's metaclass, which is necessary as the superclass's class methods should be available as the subclass's class methods.

Modifying the question code a bit:

$old_classes = []
def print_objects
  new_classes = []
  ObjectSpace.each_object(Class){|x| new_classes << x}
  puts "New classes: #{new_classes - $old_classes}" unless $old_classes.empty?
  puts "Counts: #{ ObjectSpace.count_objects[:T_CLASS] }"
  $old_classes = new_classes
end

print_objects

class Test
end
puts 'Test class created'
print_objects

class Test
  def self.foo
  end 
end
puts 'Test singleton class referenced'
print_objects

I get the following results:

Counts: 690
Test class created
New classes: [Test]
Counts: 692
Test singleton class referenced
New classes: [#<Class:Test>]
Counts: 693

I tried it with Ruby 2.6 and 2.0 both inside and outside a console (the numbers differ but the difference is the same) and @SajibHassan with 1.9.3 (version in which the method count_objects was introduced). This means that the difference has always been 3 and that the first singleton class created is not accessible for the user.

The book Ruby Under a Microscope (written in 2012 after the release of Ruby 2.1) also describes the creation of only two metaclasses, which doesn't match the result we get.

Note that methods like Module#prepend (introduced in Ruby 2.0), which was mentioned by @JörgWMittag in the comments as the possible reason for this extra class, use T_ICLASS. Check the commit in which the method was introduced for details. I guess that T_ICLASS stands for internal class and consequently internal classes shouldn't be visible to the user (which makes sense). I am not sure though why some T_CLASS are accessible to the user and some others are not.

like image 68
Ana María Martínez Gómez Avatar answered Oct 10 '22 01:10

Ana María Martínez Gómez