Friday, August 5, 2011

Adding methods at runtime in javascript, ruby, and java

OK, the title is a ruse, you can't easily add methods to java classes at runtime. But I'll illustrate how to do it in javascript and ruby. For example, lets supposed we have a javascript object(function) and we want to add a say_hello method to it:

var myObj = {};
myObj.say_hello() // doesn't work
myObj.say_hello = function() {
  return "hello";
}
myObj.say_hello(); //works


This is because javascript treats functions as first class citizens and doesn't even bother with the concept of "classes" as something other than special functions.

Same thing in ruby:
myObj = Object.new
myObj.say_hello # doesn't work
def myObj.say_hello
  "hello"
end
myObj.say_hello # works

There's a subtle difference here. The ruby syntax seems a little strange to me and it wasn't obvious how to do this. In javascript, it's very obvious that you're assigning a new function to the attribute (that you're adding). In ruby, using def in this manner seems out of place...

Ruby seems to attribute special meaning to the class and object definition where javascript treats methods (functions) just like any other variable.

Digging around a little, the ruby situation gets a little strange:

myObj2 = Object.new;
myObj2.say_hello @ doesn't work (this makes sense because we only defined the method on one instance
Object.respond_to? :say_hello #false ??? I "kinda" get it
myObj.respond_to? :say_hello #nil  ??? OK, now I'm pretty confused


If I want, I COULD have added the method to the class in ruby and then every instance would get it e.g.
myObj = Object.new()
myObj.say_hello # doesn't work
class Object
  def say_hello
    "hello"
  end
end
myObj.say_hello # works
myObj2 = Object.new()
myObj2.say_hello #works
MyThing.respond_to? :say_hello #works


It really depends on if you want to "backport" new methods to all objects of a class or only add the method to a particular instance. To do the equivalent in javascript, you'd do something like
var myObj = {};
myObj.say_hello() // doesn't work
Object.prototype.say_hello = function() {
  return "hello";
}
myObj.say_hello(); //works
var myObj2 = {};
myObj2.say_hello() //works
(new Array()).say_hello() //works!


The difference between how the two languages accomplish this is pretty minor, the more important thing to understand is the difference between adding a method to and instance (object) or a class definition(prototype). Not having a complete understanding of these differences can cause a lot of problems and subtle bugs in your code.

2 comments:

MyHeadHurts said...

:( "Adding methods at runtime in blah, blah, and JAVA" - i was so exited i finally found something useful ...

Anonymous said...

Title is misleading.