Reputation: 3194
Can someone explain the relation between the Ruby class interrelation diagram and the way method lookup is done in the actual Ruby C code?
Interrelation diagram from https://ruby-doc.org/core-2.5.3/Class.html:
+---------+ +-...
| | |
BasicObject-----|-->(BasicObject)-------|-...
^ | ^ |
| | | |
Object---------|----->(Object)---------|-...
^ | ^ |
| | | |
+-------+ | +--------+ |
| | | | | |
| Module-|---------|--->(Module)-|-...
| ^ | | ^ |
| | | | | |
| Class-|---------|---->(Class)-|-...
| ^ | | ^ |
| +---+ | +----+
| |
obj--->OtherClass---------->(OtherClass)-----------...
and the lookup in Ruby code seems to traverse RClass's super
member as a flat list here: pseudocode
while (!st_lookup(RCLASS(klass)->m_tbl, ...)) {
klass = RCLASS(klass)->super;
...
}
Where in the above diagram would the internal RClass.super
and RBasic.klass
(C structures)
pointer-arrows be mapped ? Which path would the method lookup take in this diagram? In particular the diagram seems to contain cycles. How is that to be interpreted? What does the ...
in
obj--->OtherClass---------->(OtherClass)-----------...
mean (singleton of a singleton ?), how is singleton of a singleton accessed in Ruby and how is it modeled in the C implementation?
Upvotes: 0
Views: 58
Reputation: 3194
I diggged around a bit and the ancestor
function seem to traverse the RClass.super c-struct member, the same as the method looup does. So when I do a
class OtherClass end
obj = OtherClass.new
obj.class.singleton_class.singleton_class.ancestors =>
[#<Class:#<Class:OtherClass>>, \
#<Class:#<Class:Object>>, \
#<Class:#<Class:BasicObject>>, \
#<Class:Class>, \
#<Class:Module>, \
#<Class:Object>, \
#<Class:BasicObject>, \
Class, \
Module, \
Object, \
Kernel, \
BasicObject]
BasicObject
^ +---------+ +--------+
| | | | |
Kernel | #<Class:BasicObject> | #<Class:#<Class:BasicObject>>
^ | ^ | ^
| | | | |
Object | #<Class:Object> | #<Class:#<Class:Object>>
^ | ^ | ^
| | | | |
+-------+ | +--------+ | |
| | | | |
Module | #<Class:Module> | |
^ | ^ | |
| | | | |
Class | #<Class:Class> | |
^ | ^ | |
+---+ +--------+ |
|
obj--->OtherClass --->#<Class:OtherClass>--->#<Class:#<Class:OtherClass>>
That means the vertical arrows in the diagram can be seen as the RClass.super
c-member traversal. The horizontal arrows on the other hand should be related to RBasic.klass
, however the Ruby code seems asymetric.
...
|
obj---> OtherClass
When a singleton class is created the former RBasic.klass
will get the RClass.super
of the new singleton class.
... ...
Object #<Class:Object>
^ ^
| |
OtherClass |
^ |
| |
obj--->#<Class:#OtherClass:0x...> ->#<Class:OtherClass> -+
^-+
and going one step futher a singleton of a singleton then looks like:
... ... ...
Object #<Class:Object> #Class<#<Class:Object>>
^ ^ ^
| | |
OtherClass | |
^ | |
| | |
obj-->#<Class:#OtherClass:0x...>-->#<Class:OtherClass>-->#<Class:#<Class:OtherClass>>-+
^-+
The meaning/usage of a singleton class is understandable, however there meaning/usage of the metaclasses is a bit esoteric.
Upvotes: 1