Ruby Object Model
Ruby Object Model
@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
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)
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)
(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);
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();
rb_mKernel = rb_define_module("Kernel");
rb_include_module(rb_cObject, rb_mKernel);
(object.c)
?
Make me a Dog
VALUE
rb_define_class_id(ID id, VALUE super)
Default super is Object
{
VALUE klass;
}
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)
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);
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
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...
// ...
}
(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...
// ...
}
(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
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
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
module B
extend A # should I expect this to work??
end
C.a_method
module C
extend B
end