0% found this document useful (0 votes)
76 views

Ruby Object Model

The document discusses Ruby's object model and metaprogramming concepts like classes, metaclasses, and singleton classes. It provides code examples demonstrating how Ruby initializes its core class hierarchy and constructs new classes and metaclasses. Key structs like RObject, RClass, and RBasic that represent Ruby objects are described along with how method lookup and dispatch works.

Uploaded by

cona
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
76 views

Ruby Object Model

The document discusses Ruby's object model and metaprogramming concepts like classes, metaclasses, and singleton classes. It provides code examples demonstrating how Ruby initializes its core class hierarchy and constructs new classes and metaclasses. Key structs like RObject, RClass, and RBasic that represent Ruby objects are described along with how method lookup and dispatch works.

Uploaded by

cona
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 120

hello

@tjjjwxzq
All I'd Wanted to
Know About
Ruby's Object Model
Starting Out
...And
Moooarr!!!
YAEYYY
FREE RDRC
TICKETS!!!!!!!
stuff = %w(
breathe read wonder introspect
learn code write improve marvel
laugh cry connect love sing draw
teach create receive give rejoice
struggle remember forget suffer
paint wander ramble believe live
)

while 'life' do
stuff.sample
end
def turn_your_block_into_a_shiny_proc(&block)
puts "Did I mention that procs are kinda tricksy?"
block.call
end

turn_your_block_into_a_shiny_proc do |tricksy|
puts "I #{tricksy ? "am" : "am not"} tricksy"
end
class DangerousThing
def consume
[:increase_insurance_premium]
end
end

class Cupcake < DangerousThing


include Icing

def consume
super + (add_icing << :lots_of_calories)
end
end

module Icing
def add_icing
[:moar_calories]
end
end
default definee

eigenclass
singleton
method

class
instance
metaclass variables

extend
default definee

eigenclass
singleton
method

class
instance
metaclass variables

extend
V A L UE
p t r _ t
f u i nt
y p e d e
t

#defi
ne R_
CAST(
st) (
struc
t st*
)
INTROSPECTION
class Dog
# ...
end

doge = Dog.new
doge.class
doge.class # => Dog
Dog.class # => Class
Dog.superclass # => Object
BasicObject.class # => Class
Object.class # => Class
Module.class # => Class
Class.class # => Class
def doge.speak(word)
@modifiers |= %w(so very many much such)
"#{@modifiers.sample} #{word}"
end
def doge.speak(word)
@modifiers |= %w(so very many much such)
"#{@modifiers.sample} #{word}"
end
def doge.speak(word)
@modifiers |= %w(so very many much such)
"#{@modifiers.sample} #{word}"
end
doge.class # => Dog
doge.singleton_class
# => #<Class:#<Dog:0x00000000d3ae50>>
IT'S OVER 9000!!!!
The
End
struct

...
obj
members
...
3 structs we care about
struct RObject { struct RClass {
struct RBasic basic; struct RBasic basic;
union { VALUE super;
struct { rb_classext_t *ptr;
uint32_t numiv; struct rb_id_table *m_tbl;
VALUE *ivptr; };
void *iv_index_tbl;
} heap;
VALUE ary[ROBJECT_EMBED_LEN_MAX];
} as;
};

RObject RClass
(include/ruby/ruby.h) (internal.h)

struct RBasic {
VALUE flags;
const VALUE klass;
}

RBasic
(include/ruby/ruby.h)
RBasic
Metadata
what type of object?
(T_OBJECT, T_CLASS,
struct RBasic { T_MODULE etc.)
VALUE flags; singleton class?
const VALUE klass;
} (FL_SINGLETON)

'True' class
pointer to RClass struct
RObject
RBasic plus stuff

struct RObject {
struct RBasic basic;
union {
struct { Instance variables
uint32_t numiv;
VALUE *ivptr; pointer to the heap
void *iv_index_tbl;
} heap; OR
VALUE ary[ROBJECT_EMBED_LEN_MAX];
} as; embedded directly
};
RClass
Normal objects are stored as RObject, class objects as
RClass
'True' superclass
pointer to RClass struct
struct RClass {
struct RBasic basic; Class Extension Struct
VALUE super;
rb_classext_t *ptr; class instance
struct rb_id_table *m_tbl; variables
};
class constants...
Method table
store instance methods
Method Dispatch
static inline rb_method_entry_t*
search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
{
Keep searching
rb_method_entry_t *me;
method tables
for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
if ((me = lookup_method_table(klass, id)) != 0) break; of supers till
}
we find
if (defined_class_ptr)
*defined_class_ptr = klass; something
return me;
}

(vm_method.c)

klass super super

doge.class
Where does it begin?
Bootstrap
void
InitVM_Object(void)
{
Init_class_hierarchy();

#undef rb_intern
#define rb_intern(str) rb_intern_const(str)

rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);


rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0);
rb_define_method(rb_cBasicObject, "!=", rb_obj_not_equal, 1);

rb_define_private_method(rb_cBasicObject, "singleton_method_added", rb_obj_dummy, 1);


rb_define_private_method(rb_cBasicObject, "singleton_method_removed", rb_obj_dummy, 1);
rb_define_private_method(rb_cBasicObject, "singleton_method_undefined", rb_obj_dummy, 1);

// ... really long function ...

(object.c)
Bootstrap
void
Init_class_hierarchy(void)
{
rb_cBasicObject = boot_defclass("BasicObject", 0);
rb_cObject = boot_defclass("Object", rb_cBasicObject);
rb_gc_register_mark_object(rb_cObject);

/* resolve class name ASAP for order-independence */


rb_class_name(rb_cObject);

rb_cModule = boot_defclass("Module", rb_cObject);


rb_cClass = boot_defclass("Class", rb_cModule);

rb_const_set(rb_cObject,
rb_intern_const("BasicObject"), rb_cBasicObject);

RBASIC_SET_CLASS(rb_cClass, rb_cClass);
RBASIC_SET_CLASS(rb_cModule, rb_cClass);
RBASIC_SET_CLASS(rb_cObject, rb_cClass);
RBASIC_SET_CLASS(rb_cBasicObject, rb_cClass);
}

(class.c)
Where's Kernel?
Bootstrap
void
InitVM_Object(void)
{
Init_class_hierarchy();

// ... bunch of stuff ...

rb_mKernel = rb_define_module("Kernel");
rb_include_module(rb_cObject, rb_mKernel);

// ... really long function ...

(object.c)
?
Make me a Dog

VALUE
rb_define_class_id(ID id, VALUE super)
Default super is Object
{
VALUE klass;

if (!super) super = rb_cObject;


Create the new RClass
klass = rb_class_new(super);
rb_make_metaclass(klass, RBASIC(super)->klass);
struct with given super

}
return klass; Make and set Dog's
metaclass straightaway
(class.c) (ignore the second parameter, it is unused)
Terminology...

Singleton class
= eigenclass

Metaclass
Terminology...
Metaclasses are also classes, so...

Metametaclasses

Metametametaclasses

Metametametametaclasses

Meta^(n)classes
Make me a <Dog> (class.c)

static inline VALUE make_metaclass(VALUE klass)


{
VALUE super; Initialize metaclass as new
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON); 1 RClass struct; set singleton flag;


rb_singleton_class_attached(metaclass, klass);
(attach Dog class to metaclass)
if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass); Set Dog's klass to point
SET_METACLASS_OF(metaclass, metaclass);
}
to the new metaclass;
else {
VALUE tmp = METACLASS_OF(klass);
2
SET_METACLASS_OF(klass, metaclass); Set metclass's klass to
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
} point to...what?
super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass); 3
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
Set metaclass's super to point to...what?
Make me a <Dog>
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);

if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, metaclass);
}
else {
VALUE tmp = METACLASS_OF(klass);
SET_METACLASS_OF(klass, metaclass);
/* SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
}

super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);

OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;*/
}
Make me a <Dog>
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);

if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass); Set Dog's klass to point
SET_METACLASS_OF(metaclass, metaclass);
}
to the new metaclass;
else {
VALUE tmp = METACLASS_OF(klass);
2
SET_METACLASS_OF(klass, metaclass); Set metclass's klass to
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
} point to...what?
super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);

OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
Make me a <Dog>
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON); tmp is whatever Dog's


rb_singleton_class_attached(metaclass, klass);
klass points to before
if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass); 2 we set it to the new
SET_METACLASS_OF(metaclass, metaclass);
} metaclass.
else {
VALUE tmp = METACLASS_OF(klass); tmp = Class
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
} This macro calls
super = RCLASS_SUPER(klass); make_metaclass(Class)
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
The Dog metaclass's
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);

OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass)); klass points to the Class


return metaclass; metaclass!
}
Make me a <Class>
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);
The Class metaclass's
klass points to itself!
if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass); 2
SET_METACLASS_OF(metaclass, metaclass); (just like how Class's klass
}
else { used to point to itself)
VALUE tmp = METACLASS_OF(klass);
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
}

super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);

OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
make_metaclass(Dog)

make_metaclass(Class)
Make me a <Class>
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);

if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, metaclass);
} The superclass of the Class
else {
VALUE tmp = METACLASS_OF(klass); metaclass is the metaclass of
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp)); Class's superclass
}

super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass); 3
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
make_metaclass(Dog)

make_metaclass(Class)

make_metaclass(Module)
make_metaclass(Dog)

make_metaclass(Class)

make_metaclass(Module)

make_metaclass(Object)
make_metaclass(Dog)

make_metaclass(Class)

make_metaclass(Module)

make_metaclass(Object)

make_metaclass(BasicObject)
super of <BasicObject>?
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);

if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, metaclass);
}
else {
VALUE tmp = METACLASS_OF(klass); The superclass of the
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp)); BasicObject metaclass is Class
}

super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass); 3
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
super of <Dog>?
static inline VALUE make_metaclass(VALUE klass)
{
VALUE super;
VALUE metaclass = rb_class_boot(Qundef);

FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);

if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
SET_METACLASS_OF(klass, metaclass);
SET_METACLASS_OF(metaclass, metaclass);
}
else { The superclass of the Dog
VALUE tmp = METACLASS_OF(klass);
SET_METACLASS_OF(klass, metaclass); metaclass is the metaclass of
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
} Dog's superclass
super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass); 3
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

return metaclass;
}
CONGRATULATIONS

Boromir was right


Make me a <doge>
static inline VALUE make_singleton_class(VALUE obj) Initialize singleton class as new RClass
{
VALUE orig_class = RBASIC(obj)->klass; struct whose super is the original
VALUE klass = rb_class_boot(orig_class);
FL_SET(klass, FL_SINGLETON); 1 class; set singleton flag

RBASIC_SET_CLASS(obj, klass); Set doge's klass to point to the new


rb_singleton_class_attached(klass, obj); 2 singleton class

3
SET_METACLASS_OF(klass, METACLASS_OF(rb_class_real(orig_class)));
return klass;
}
Set the doge singleton class's klass to
point to the Class metaclass

(class.c)
Wait, what about
modules?
Include Classes
Saberdoge
class Dog
include Saberteeth
# ...
end
Make me an include class
static int
include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
{
// check for duplicate includes, cyclic includes,
// modules included in modules, modules included in refinements...

iclass = rb_include_class_new(module, RCLASS_SUPER(c));


c = RCLASS_SET_SUPER(c, iclass);

// ...
}

(class.c)
Multiple Include Classes
class Dog
include Saberteeth
include Sunglasses
# ...
end
Make me an include class
static int
include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
{
// check for duplicate includes, cyclic includes,
// modules included in modules, modules included in refinements...

iclass = rb_include_class_new(module, RCLASS_SUPER(c));


c = RCLASS_SET_SUPER(c, iclass);

// ...
}

(class.c)

Including modules in
modules?
Modules and
Include
struct RClass {
Classes are struct RBasic basic;
VALUE super;

also RClass
rb_classext_t *ptr;
struct rb_id_table *m_tbl;
};

structs
Can modules have a
super?
Yes, but not by default
super comes in handy when we include
modules in modules
Sabersunglass Doge

module Sunglasses
include Saberteeth
end

class Dog
include Sunglasses
end
Module in a module

module Sunglasses
include Saberteeth
end
how objects and classes
are represented

singleton class and


metaclass creation

how modules work


Just to clarify...

C Ruby
klass class
super superclass
BasicObject.class # => Class
Object.class # => Class
Module.class # => Class
Class.class # => Class
Dog.class # => Class

Ruby's class
ignores singleton
classes & include
classes
class Dog
include Saberteeth
end

Dog.superclass # => Object

Ruby's superclass
ignores include
classes
class_eval vs instance_eval
include vs extend module Sunglasses class Dog
(vs prepend) include Saberteeth
end
include Sunglasses
end
vs
class Dog module Sunglasses
class << self; end include Sunglasses include Saberteeth
end end

class variables vs class instance variables


module A
def a_method; end
end

module B
extend A # should I expect this to work??
end
C.a_method
module C
extend B
end

You might also like