Skip to content


Java Programmer’s Guide to Ruby Metaclasses

I finally got my head wrapped around Ruby metaclasses — what a trip! So if you’re a Java programmer trying to understand metaclasses, maybe this will help.

There are many great resources on Ruby metaclasses, but none of them really quite worked for me. Good or bad, Java is still my “native” language, so when I’m doing new things in other languages it helps for me to “translate” it back into Java — in other words, I think, “how would I do this in Java?” Since there is nothing like metaclasses in Java, we’ll have to use our imagination.

Let’s pretend that for whatever reason, you want to add an instance method to an object, at runtime. How would you do it in Java? This is how I imagine you would do it, if you *could* do it:

// create a method that looks like this: 
//   public void sayHello() { System.out.println("Hello!"); }
Method sayHelloMethod = new Method(Method.PUBLIC, Method.VOID, "sayHello", new Class[] {}, "System.out.println(\"Hello!\");");

MyObject myFirstObject = new MyObject();
/*
 * This is where you need your imagination, imagine that java.lang.Object had
 * a method named addMethod()...
 */
myFirstObject.addMethod(sayHelloMethod); // add the sayHello method to our object

// now use it!
myFirstObject.sayHello();  //=> prints "Hello!" to standard out...

MyObject mySecondObject = new MyObject();
mySecondObject.sayHello(); //=> throws a NoSuchMethodError

Quasi-straightforward, right? We told the JVM that we wanted the myFirstObject object to have a new method. But the mySecondObject doesn’t have the sayHellomethod. Once you have a good feel for that, look to see how it’s done in Ruby:

my_first_object = MyObject.new
class << my_first_object
  def say_hello
    puts "Hello!"
  end
end
my_first_object.say_hello #=> "Hello!" printed to standard out
my_second_object = MyObject.new
my_second_object.say_hello #=> undefined method `say_hello' for #<MyObject:0x25210> (NoMethodError)

Alright, but what if we want all instances of MyObject to have a sayHello method? Let’s imagine how we might do it in Java:

// create a method that looks like this: 
//   public void sayHello() { System.out.println("Hello!"); }
Method sayHelloMethod = new Method(Method.PUBLIC, Method.VOID, "sayHello", new Class[] {}, "System.out.println(\"Hello!\");");
Class myObjectClass = Class.forName("MyObject");
myClass.addInstanceMethod(sayHelloMethod);
((MyObject) myObjectClass.newInstance()).sayHello();   //=> prints "Hello!"
((MyObject) myObjectClass.newInstance()).sayHello();   //=> prints "Hello!" again

This time instead of just modifying the single instance of MyObject we changed the class, so all instances have the method. Let’s do the same in Ruby:

MyObject.send :define_method, :say_hello do
  puts "Hello!"
end
MyObject.new.say_hello #=> print "Hello!"
MyObject.new.say_hello #=> print "Hello!"

Good enough. From now on all instances of MyObject (including the ones instantiated before we added this method!) will have a say_hello method. Pretty cool.

Finally we can add static methods as well, once again imagining in Java…

Method sayHelloMethod = new Method(Method.PUBLIC, Method.VOID, "sayHello", new Class[] {}, "System.out.println(\"Hello!\");");
Class myObjectClass = Class.forName("MyObject");
myObjectClass.addStaticMethod(sayHelloMethod);
MyObject.sayHello  //=> prints "Hello!"

And the same thing in Ruby:
class << MyObject
  def say_hello
    puts "Hello!"
  end
end
MyObject.say_hello #=> prints "Hello!"

Posted in Java, Ruby, Software Development, Tips and Tricks.


0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.



Some HTML is OK

or, reply to this post via trackback.