Синглтон-класс синглтон-класса BasicObject в Ruby
Это в основном "академический", но здесь это идет:
Согласно этой диаграмме собственного класса Ruby (слегка отредактировано):
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 ответ
Поведение интерпретатора 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
Это приводит к следующему вопросу - почему #<Class:BaseObject>
простираться Class
на первом месте? Следуя правилу выше, так как BaseObject
не имеет суперкласса, то есть BaseObject.superclass
является nil
- логично было бы, чтобы у его синглтон-класса не было суперкласса.
Ответ в том, что #<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
, пройдя по цепочке наследования, она в конце концов доберется...