Using instance variables in class methods in Ruby
I was looking at some legacy Ruby code today and saw that there was a bunch of instance variables being created inside a class method. In fact, the whole class is littered with
def self.foo declarations; nothing except class methods. There was an even funky statement at the top of the class.
class Foo class << self attr_reader :instance_var_1, :instance_var_2, :instance_var_3 end ... end
Needless to say, I was intrigued. Who would write Ruby code this way? What was the intent and motivation? Was it laziness or awesomeness? Was there some intricacies of Ruby that I was not aware of? That must be it. Faced with something I know I don’t know, naturally, I wanted to experiment. Off to the REPL I say..
class Foo def self.bar=(val) @bar = val end def self.bar @bar end end
So I created my own dummy class to work with. Standard enough getter/setter but using a class method.
Foo.bar = "hello world" => "hello world" Foo.bar => "hello world"
Works as expected. Now to unknown territory.
a = Foo.new => #<Foo:0x007f95ab80d5e8> b = Foo.new => #<Foo:0x007f95aa17e688> a == b => false
Again, as expected.
a.class.bar => "hello world" b.class.bar => "hello world"
a.class.bar = 12345 => 12345
So what happens when I call #bar from b?
b.class.bar => 12345
Interesting! Since Foo is an instance of Class, the instance variable @bar lives on that instance. Any sub-instances we create from Foo and then subsequently attempt to access @bar will look at the same reference.
So the moral of the story: while it is fine to use instance variables in class methods, you probably shouldn’t.