class reloading and constants

X

Xavier Noria

Context: I am trying to understand how does Rails implement class
reloading.

If we reload a .rb file that defines class A::B with Kernel#load we
are just reopening the class, so that's poor man's reloading in the
sense that redefined methods are updated, but removed methods are
still there.

I guess (it is just a guess) that's the reason Rails does black magic
with constants in Class#remove_class. I think the key line there is

parent.send :remove_const, basename unless parent == klass

which removes the basename of the class we want to remove from the
constants in its parent module, if any. The irb session below
suggests that technique triggers a "fresh" reload of the class, but
why? A posteriori one would bet a class definition reopens the class
if there's already a class object in that constant, and just
instantiates a new one otherwise, is that right?

-- fxn

fxn@feynman:~/tmp$ irb
irb(main):001:0> IO.read('foo.rb')
=> "module A\n class B\n def x\n 'x'\n end\n end\nend"
irb(main):002:0> load 'foo.rb'
=> true
irb(main):003:0> A::B.new.x
=> "x"
irb(main):004:0> A::B.object_id
=> 1683700
irb(main):005:0> A.send:)remove_const, 'B')
=> A::B
irb(main):006:0> IO.read('foo.rb')
=> "module A\n class B\n def y\n 'y'\n end\n end\nend"
irb(main):007:0> load 'foo.rb'
=> true
irb(main):008:0> A::B.new.x
NoMethodError: undefined method `x' for #<A::B:0x59f27c>
from (irb):8
from :0
irb(main):009:0> A::B.new.y
=> "y"
irb(main):010:0> A::B.object_id
=> 2952610
 
X

Xavier Noria

which removes the basename of the class we want to remove from the
constants in its parent module, if any. The irb session below
suggests that technique triggers a "fresh" reload of the class, but
why? A posteriori one would bet a class definition reopens the
class if there's already a class object in that constant, and just
instantiates a new one otherwise, is that right?

I reply to myself :). Looking at the source code in class.c that's
indeed the case:

VALUE
rb_define_class(name, super)
const char *name;
VALUE super;
{
VALUE klass;
ID id;

id = rb_intern(name);
if (rb_const_defined(rb_cObject, id)) {
klass = rb_const_get(rb_cObject, id);
...
return klass;
}
...
klass = rb_define_class_id(id, super);
...
return klass;
}

Understood!

-- fxn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top