What happens when you call Object.new?
by Paweł Świątkowski
15 May 2015
While reading RubyGems source code for second or third time this week, I encountered something weird, which led me to this little investigation. Namely, in one class there was a constructor with def initialize
, but just above it there was a static method definition with def self.new
. How did it work? Soon I found out.
MyClass.new
obviously looks like calling a class static method, though I always thought that there is some magic involved there, which chose to call initialize
instead. Turned out I was wrong. Luckily MRI’s code is readable enough to track it there. So, let’s have a look:
This is what static method new
of class Object
looks like. We can see some memory allocation there and then rb_obj_call_init(obj, argc, argv)
which, as one could guess, calls initialize
of newly allocated object. And one would be right:
Even though PASS_PASSED_BLOCK
is some kind of weird macro I don’t really understand (yes, my C-fu is weak), it is followed by something that clearly looks like calling a idInitialize
(which is an alias for “initialize” word from REGISTER_SYMID(idInitialize, "initialize");
) on obj
with arguments.
For reference, this is how Rubinius implements it:
So, what can we use this knowledge for? Let’s jump back to RubyGems source. The overridden self.new
there looks like this:
Basically, there are some checks on the argument and then, if those indicate old format of the gem, different class is instantiated and returned. Familiar? Well, yes, this sounds more or less like Factory design pattern. And we can use it for that. Consider following code:
Pretty neat, huh? There is, however one big caveat here: the other class you are instantiating cannot inherit from the class that is being called or you end up with stack level too deep, which is completely understandable. Another way to do it is to define self.new
in children classes as follows:
This might not be the most useful trick in the world, but experimenting with it brought me closed to understand how Ruby works.