A good understanding of method dispatch can help in deciphering some of the odder corners of the Ruby object model. Luckily, method dispatch is not only straight forward, but entirely consistent for “normal” methods, singleton methods, and module methods.
In Matz’s Ruby Interpreter (MRI), method bodies are stored in a struct devoted to representing an instance of a Ruby class. It’s called an RClass (appropriately enough) and looks like this:
The bits to pay attention to here are struct st_table *m_tbl and VALUE super.
st_table is a C Hash implementation used liberally by the MRI. *m_tbl is a pointer to a hash that stores method bodies indexed by the method name (or selector for the Smalltalk heads among us).
The VALUE type is a pointer to a struct representing some sort of Ruby “thing” (class object, etc). This is actually not true for some special types called immediate types (fixednums, symbols, true, false and nil), but it’s true for everything else in the Ruby world. Don’t get too hung up on immediate types, the thing to know is that super is generally pointing to another RClass struct.
That’s all you need to know about Ruby internals to understand dispatch. The sequence of steps are always:
1) A message is sent to an object.
2) The klass pointer on the object is dereferenced to get access to the Class of the object (usually represented by an RClass).
3) The *m_tbl is checked for a matching method name.
4) if the method is found, the body is returned for evaluation, otherwise the super pointer is followed and step 3 and 4 are repeated.
5) If the super pointer returns null, the method wasn’t found anywhere in the inheritance chain and method missing is called.
Don’t take my word for it. The 1.8.6 source for looking up a method is below. klass is a reference to the class of the object, id is the name of the method. origin is used to store a reference to the class that actually contained the method.