Okay, so I'm trying to do some metaprogramming in Ruby and I'm getting a bit confused. According to several articles I've read (like this one), in order to dynamically add class methods to Ruby classes, you have to use the class's singleton class:
class Klass
end
class << Klass
self.define_method(:foo) { return "foo" }
end
Why is this, and how is that different from this?
class Klass
self.define_method(:foo) { return "foo" }
end
(Sorry if this question contains any false assumptions. Like I said, I'm a bit confused.)
To answer your question directly:
Module#define_method
creates an instance method. A "class method" is an instance method on the singleton class (or eigenclass) of aClass
object. I'm sure that sounds very confusing. Let me explain why Ruby includes the concept of "singleton classes" in the first place:First, let me say that the basic "framework" of different object-oriented languages are quite varied. Ruby's design as regards objects, classes, metaclasses, etc. is by no means the only possible one, and the language could have been designed in a different way. Having said that, there are logical reasons why Ruby works the way it does. I'll try to explain as concisely as possible...
Think of a simple method call, like:
Here we are calling a method called
first
, with anArray
object as receiver. To process this method call, Ruby needs to search for a matching method definition, and execute it. Where does it start looking? Naturally, in the instance methods ofArray
. If it doesn't find it there, it will look inArray
's superclass, then the superclass of the superclass, as well asModule
s which are mixed intoArray
or its superclasses, etc."Class-based" (as opposed to prototype-based) object-oriented languages all work this way, more or less. If you've ever programmed in Java, or C++, or Python, this behavior should be familiar to you.
Now, the creator of Ruby wanted to also make it possible to add methods to just one object. In a prototype-based OO language, that would be easy, but how could it work in a class-based language? He made it possible by introducing the idea of "singleton classes" or "eigenclasses".
A "singleton class" is, simply, a class which has only one instance. I believe that rather than trying to keep track of a different singleton class for every single object, Ruby waits until the first time you try to access an object's singleton class, and then creates the class and inserts it into the object's inheritance chain dynamically.
As I just said, when a method is called, Ruby looks first in the object's class to find a matching definition, then the superclass, etc. Since singleton classes are inserted as the first link in an object's inheritance chain, they are the first place which Ruby will look for a method definition.
Bringing in the concept of "singleton classes" also solved another problem at the same time. In Java (for example), you can define
static
methods which are called on a class. In Ruby, people often want to do something similar. With "singleton" classes and methods, you can do just that: all you have to do is define a singleton method on a Class object.(Remember that classes are also objects in Ruby. That's why the concept of "singleton" classes and methods can "kill 2 birds with 1 stone", as I explain above!)
EXTRA INFORMATION:
At the beginning, I mentioned "instance methods". I don't know if that might be confusing, or if you already know what "instance methods" are. When you define a Ruby class, like this...
...then
my_method
will be added as an instance method ofMyClass
. When Ruby searches an object's class, superclass, etc. for a method definition, what it actually looks at are their instance methods. So an object's "methods" are the instance methods of its class, plus the instance methods of the superclass, the superclass of the superclass, etc.About how singleton classes interact with method lookup in Ruby, there is a slight inconsistency which I didn't mention above. If you want to understand in detail:
Singleton classes of class objects are treated a little differently from singleton classes of other objects in general. If you have a class
A
which inherits from another classB
, andB
has singleton methods,A
will inherit not just the instance methods, but also the singleton methods ofB
. In other words,B
's singleton class is treated as a superclass ofA
's singleton class. This is not true of the singleton classes of any other objects.