Travis Emmett's blog

A coder in training's thoughts

Dude, Where's My Object?

I love things that expose a little bit of what Ruby is doing under the hood. And I’m new to object orientation so you will just have to humor me here. Let’s say you’re in IRB and you just created a shiny new Car class with the following Ruby code:

1
2
3
4
5
6
7
8
9
10
11
class Car
attr_accessor :make, :model, :year
  def initialize(make, model, year)
    @make = make
    @model = model
    @year= year
  end
  def drive
    puts "Vrooom!"
  end
end

And now you decide you’re ready to create a new car so you can get ready to take it for a spin with the following code:

1
Car.new("Renault", "LeCar",  1979)

Renault LeCar? Nice choice! Now, let’s ride. But wait, you forgot to assign your new car to a variable. Dude, where’s your car?

Well, as it turns out, it’s not actually gone. It just requires a little snooping around to get it back. Ruby comes packaged with a module called ObjectSpace which contains a useful method #each_object to aid in the search. ObjectSpace interacts with Ruby’s garbage collection facility which helps manage Ruby’s memory. Calling #each_object and passing in your class in question will allow you to find all living objects of that particular class (assigned to a variable or not):

1
2
3
4
ObjectSpace.each_object(Car){|car| puts car.object_id}
#IRB output
  #70206505370260
  #=> 1

Ruby returns to you the number of objects in the Car class ‘1’ and your missing car’s object id, provided you #puts it (70206505370260). If you had a bunch of objects in that class instead of just one like we do, you could pass in the value of a particular instance variable of your object in question into the block through an if statement to narrow down your search.

But I digress. Now that you are armed with this information, you can use another method in ObjectSpace called #_id2ref which converts an object id into a direct reference to the object to finally track down your car and save it:

1
2
3
4
5
6
lecar = ObjectSpace._id2ref(70206505370260)
#IRB output
=> #<Car:0x007fb473a08528 @make="Renault", 
#@model="LeCar", @year=1979>

lecar.drive ==> "Vroom!"

Way to go! You even remembered to store your car to a variable this time so this will not happen again. Jesse and Chester would be proud.

Now, if you want to have some more fun, ever wonder what other objects Ruby has hidden under the rug? Try this line of code in IRB sometime to see what strings Ruby currently has in memory. It yielded an array of 23,157 strings I did not know about!

1
2
3
strings_array = [ ]
ObjectSpace.each_object(String){|string| strings_array << (ObjectSpace._id2ref(string.object_id))}
strings_array

What’s yours say? SWEET!