Method Resolution in Ruby
While reading the Ruby Pickaxe book I realized that while JavaScript and Ruby are both dynamic languages, they handle method resolution in very different ways. I often use JavaScript as a reference since it’s the dynamic language I’m most familiar with.
A Simple Example in JavaScript
Let’s first look at a simple JavaScript example.
This will run without any problems. If you try to get the value of a property that doesn’t exist JavaScript will simply return undefined. If you try to set a property that doesn’t exist JavaScript will create that property and set the value. JavaScript will complain when you try to invoke a method that doesn’t exist.
If I recall correctly, dynamic objects in C# 4.0 will function the same way – you can add properties to a dynamic object without problems, but invoking a method will raise an error. (It’s been a while since I worked in C#, so don’t quote me on that)
Ruby doesn’t have the concept of properties, so in the following snippet of Ruby code,
Ruby is actually looking for a method called name= and passing the string “Wobble” as a parameter.
A Simple Example in Ruby
Let’s try the same example in Ruby.
As you might expect, Ruby raises an error saying there is no name= method on this object.
There are a couple of ways we can get around this limitation. The simplest is probably to add a name accessor to the class.
As you can see from the example, Ruby allows us to add accessors for a @name instance variable to the class. The attr_accessor method (also called a Macro) will add the necessary methods to access this attribute – in other words, it’s similar to adding the following two methods:
It’s important to know that the attr_accessor method doesn’t actually create the @name instance variable – it will be created the first time we access it.
Using method_missing
Ruby also allows us to define a method_missing method (also called a Hook) which will be invoked when a method is not found (as you might deduce from the name). It has a pretty simple signature:
So we have the name of the method being called (passed as a symbol), the arguments passed as a splat array, and a block.
We can now put this to use to allow us to dynamically access any instance variable.
Conclusion
I definitely wouldn’t advocate using this type of code in a real project, but it’s interesting to see what’s possible.
Happy coding.