Reverse Superclass Envy and Bad Mental Pointers
I’ve ranted previously about Python and made promises of future posts about why Ruby is so much cooler. It really is and the topic of this article covers one of the common idioms used by most Ruby folks who may have taken a shot at their own domain specific language in Ruby. The following is one of the really useful idioms but apparently not a very well understood or well explained one for Ruby coders.
To many Ruby folks this is the vague-but-really-really-cool-idiom that is
class << self; self; end;
This is used a lot in the Rails framework. You shouldn't have to look very deep into the Rails source code to find it. As an example I'll guess that most Ruby coders are familiar with Why's example for Dwemthy's Array that explains the idiom.
Here's the relevant bit of example code:
class Creature def self.metaclass; class << self; self; end; end ... more code for meta-programming goes here ...
traits :life, :strength, :charisma, :weapon end
This then allows the definition of other classes derived from the Creature class such as these for our example:
class GreenMonster < Creature traits :greenness, :scariness life 90 strength 45 charisma 23 weapon 80 greenness 10 scariness 12 end
class RedMonster < Creature traits :redness, :loudness life 75 strength 50 charisma 90 weapon 65 redness 20 loudness 33 end
It seems that when it comes to understanding how this idiom works most of the confusion has to do with misnaming the key feature used in the Creature class, specifically the 'metaclass' in the code above. It's usually called a meta-class(as in our example), shadow-class or class-object-instance-singleton , yikes!. (Adding in the additional popular belief that Ruby classes behave like objects can make this even more difficult to grasp. They do behave like objects but they technically are not like most objects in Ruby).
Technically the 'metaclass' is a singleton for each derived class we have but this is not as important (and probably best ignored for now) as defining what the 'metaclass' really is in terms of object-oriented meaning.
Here I offer my attempt at another simple explanation:
The idiomatic line of code is merely a hack to obtain access to the sub/derived/child class (correct OO nomenclature).
In Ruby, classes have access to their parent class via the 'superclass' method.
The equivalent method to go the other direction i.e. 'subclass' would be very useful but because there is no such method the following hack is required.
The scope that is accessible to the code between the class << self ... end block has access to the derived class scope and so 'self' is returned from the block which is then returned from the parent class method 'self.metaclass'. 'self' is the sub-class derived from Creature. In our example it's either the GreenMonster or RedMonster class.
There is no magic in this idiom when this little expletive is made clear but the way it's usually explained and the popular naming seem to be the main source of confusion.
Once you look at this for what it is, there's nothing magic except for the popular names applied to it. Maybe we should start using the more informative/explicit sub/child class naming and leave out the explanation of classes behaving as objects when explaining this useful idiom ?
or maybe that's just me in the corner, in the spotlight...