Синглтон-класс синглтон-класса BasicObject в Ruby - PullRequest
0 голосов
/ 02 июля 2018

Это в основном «академический», но здесь это так:

Согласно этой диаграмме собственного класса Ruby (слегка отредактировано):

Possibly-wrong Ruby eigenclass diagram

BasicObject.singleton_class.singleton_class.superclass - это Class.

Однако, запустив это на интерпретаторе Ruby (Ruby v2.5.1), получается, что BasicObject.singleton_class.singleton_class.superclass равен #<Class:Class>, а не Class. Таким образом, диаграмма лежит или я что-то упустил?

Диаграмма получена от пользователя, с которым я общался в Ruby IRC во Freenode. Тем не менее, он цитировался несколько раз для многих других пользователей и считался библией объектной модели Ruby.

1 Ответ

0 голосов
/ 06 августа 2018

Поведение интерпретатора Ruby имеет смысл, потому что:

  • Когда класс Child расширяет Parent, Ruby устанавливает его так, чтобы синглтон-класс #<Class:Child> также расширял #<Class:Parent>; и
  • BasicObject.singleton_class является подклассом Class, поэтому BasicObject.singleton_class.singleton_class будет подклассом #<Class:Class>

Проверка равенства:

BasicObject.singleton_class.singleton_class.superclass.equal?(Class.singleton_class)
#=> true

Это приводит к следующему вопросу & ndash; почему #<Class:BaseObject> расширяет Class в первую очередь? Следуя приведенному выше правилу, поскольку BaseObject не имеет суперкласса - ndash; то есть BaseObject.superclass - это nil & ndash; логично было бы, чтобы у его синглтон-класса не было и суперкласса.

Ответ таков: #<Class:BaseObject> расширение Class обеспечивает согласованность в иерархии наследования, когда речь идет об одноэлементных классах. Возьмите этот объект Ruby, например:

obj = "a string"

Хорошо известно, что вместо obj, являющегося просто экземпляром String, мы можем рассматривать его как (единственный) экземпляр своего собственного синглтон-класса, который, в свою очередь, является подклассом String. То есть:

obj.class.equal?(obj.singleton_class.superclass)
#=> true

Кажется логичным, что то же самое должно относиться и к экземплярам классов. Но это не так, потому что это противоречит упомянутому выше правилу, когда суперкласс класса-одиночки класса Child - это класс-одиночка его класса Parent.

class Foo; end

Foo.class
#=> Class

Foo.singleton_class.superclass
#=> #<Class:Object>      <-- not equal to Class!

# because:
Foo.superclass
#=> Object

Но это противоречие можно разрешить, поместив Class на вершину иерархии наследования синглтон-классов:

Foo.singleton_class.superclass
#=> #<Class:Object>

Foo.singleton_class.superclass.superclass
#=> #<Class:BasicObject>

Foo.singleton_class.superclass.superclass.superclass
#=> Class

Таким образом, хотя Foo.singleton_class.superclass не равно Foo.class, пройдя по цепочке наследования, он в конечном итоге доберется до места ...

...