Почему ruby создает 3 объекта после создания класса? - PullRequest
8 голосов
/ 04 апреля 2020

Я изучал метакласс Ruby. Я прочитал этот ответ , где хорошо описано, что такое метакласс. Там показано, что когда создается класс, он создает два объекта. Что понятно. Один для самого класса и один для его метакласса. Но когда я пытаюсь это сделать сам, я вижу, что он создает три объекта.

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

Я использую Ruby - 2.5.1.

Может кто-нибудь помочь мне понять это?

Обновление:

Ссылка SO , которую я добавил, использует ruby -1.9.1 или выше, так как метод count_objects для ObjectSpace был введен в 1.9.1. Кажется, что число T_CLASS всегда было 3 (пыталось с ruby-1.9.3-p551).

Итак, до сих пор остается загадкой, почему этот ответ . Ruby под микроскопом также говорит, что количество составляет 2.

1 Ответ

6 голосов
/ 14 апреля 2020

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

При создании класса автоматически создается одноэлементный класс (который недоступен для пользователя). Ссылка на одноэлементный класс класса автоматически создает одноэлементный класс этого одноэлементного класса. Это необходимо для обеспечения согласованности структуры наследования метаклассов. В противном случае методы класса не наследуются от метакласса суперкласса, что необходимо, поскольку методы класса суперкласса должны быть доступны в качестве методов класса подкласса.

Немного изменив код вопроса:

$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

Я получаю следующие результаты:

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

Я пробовал с Ruby 2.6 и 2.0 как внутри, так и снаружи консоли (цифры различаются, но разница одинакова) и @SajibHassan с 1.9.3 (версия, в которой был введен метод count_objects). Это означает, что разница всегда составляла 3 и что первый созданный синглтон-класс недоступен для пользователя.

Книга Ruby Под микроскопом (написана в 2012 году после выпуска из Ruby 2.1) также описывает создание только двух метаклассов, которые не соответствуют полученному нами результату.

Обратите внимание, что такие методы, как Module#prepend (введены в Ruby 2.0), о которых упоминалось @ JörgWMittag в комментариях в качестве возможной причины для этого дополнительного класса, используйте T_ICLASS. Проверьте фиксацию, в которой был введен метод для подробностей. Я предполагаю, что T_ICLASS обозначает внутренний класс, и, следовательно, внутренние классы не должны быть видны пользователю (что имеет смысл). Я не уверен, однако, почему некоторые T_CLASS доступны для пользователя, а другие нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...