Ramblings

22 Aug, 2008

Ruby’s ObjectSpace: Subclasses

Posted by: Matt Williams In: ruby

One of the (imho) lesser used pieces of the Ruby language is ObjectSpace.  In this article I’ll show one of the things you can do with it — get all the subclasses of a class.

ObjectSpace is almost a red-headed stepchild.  In JRuby you can even turn it off.  However, it does have its uses.

ObjectSpace has the following methods (apart from those in Object):

1
2
>> ObjectSpace.my_methods
=> ["_id2ref", "add_finalizer", "call_finalizer", "define_finalizer", "each_object", "finalizers", "garbage_collect", "remove_finalizer", "undefine_finalizer"]

ObjectSpace does allow you to take an object’s id and change it to a reference:

1
2
3
4
5
6
7
8
9
10
>> ObjectSpace._id2ref(ObjectSpace.object_id)
=> ObjectSpace
>> String.object_id
=> -605676558
>> ObjectSpace._id2ref(String.object_id)
=> String
>> "a".object_id
=> -607204778
>> ObjectSpace._id2ref(-607204778)
=> "a"

The each_object method allows one to step through all the objects in memory, performing an operation with each. This is how we’re going to get a list of subclasses:

module Subclasses
  # return a list of the subclasses of a class
  def subclasses(direct = false)
    classes = []
    if direct
      ObjectSpace.each_object(Class) do |c|
        next unless c.superclass == self
        classes << c
      end
    else
      ObjectSpace.each_object(Class) do |c|
        next unless c.ancestors.include?(self) and (c != self)
        classes << c
      end
    end
    classes
  end
end
 
Object.send(:include, Subclasses)

The code steps through the objects in ObjectSpace and returns an array of either the direct descendents, that is, ones directly subclassed from our object, or the entire tree of children.  By default it returns all the children (and their children (and …)).

So we can do the following:

>> Enumerable.subclasses
=> [Struct::Tms, Dir, File, IO, Range, Struct, Hash, Array, String, StringIO, Socket, UNIXServer, UNIXSocket, UDPSocket, TCPServer, TCPSocket, IPSocket, BasicSocket, Struct::Group, Struct::Passwd, Zlib::GzipReader, Gem::SourceIndex]

So why would we want to do this? Well, for one, it’s a good learning tool. For another, imagine a case where we don’t know all of the classes which exist in an application, however, we do know that a good number of them are subclasses of the mysterious class X. We could pass a message to all of them — telling them it’s time for dinner, perhaps, by asking X about his children. Then we message the children, letting them know it’s dinner time:

>> X.subclasses.each {|klass| klass.send(:dinner_time)}

Ok, so that last bit was contrived and I’m tuning into _why (not quite there, it’s still a bit static around the edges).

Anyone else have any uses for ObjectSpace?

2 Responses to "Ruby’s ObjectSpace: Subclasses"

1 | Pit Capitain

August 22nd, 2008 at 5:14 pm

Avatar

Hi Matt, if you search the ruby-talk archives you’ll find other, more efficient implementations for the direct == false case.

Comment Form

Categories

DrakNet Web Hosting

  • John: Hi Matt, Sorry to hear about the time wasted and that the map didn't work out for you. I've tried to design it to be easy to setup and configure.
  • Jason Jackson: Also worth noting that if your not connecting to JBoss on localhost, make sure you have DNS set up, or a host file entry, or else you will get an exce
  • Matt Williams: Yes, there's not a lot of debugging info. One thing that I've found is that if your grammar isn't constructed "properly", it won't complain and you w

Flickr PhotoStream

    layout_newm3headerTerrain Testa

About

Matt Williams is a geekly jack of all trades residing in Columbus, OH, USA.

Recommend Me


Adopt a Dragon from Dragcave
Adopt one today!Adopt one today!Adopt one today!Adopt one today! Adopt one today! Adopt one today!Adopt one today! Adopt one today! Adopt one today! Adopt one today!