This blog post is part of a series on Class Inheritance. Read Part 1 here.
I recently stumbled upon this line of code that totally floored me. I mean, I had to drop everything I was doing and do some serious Googling, my friends. Well, that and also I asked my fellow developers at work who are far more seasoned programmers than me.
Now, I’m going to share this line of code with you, but you’ve got to try not to totally freak out if you haven’t seen it before. Are you ready? Ok, here we go:
1 2 3 4 5 6 7
Are you with me? Did you make it past the second line? Do I need to call an ambulance? Well, if your reaction was anything like mine, you saw
class << self and experienced something akin to an aneurysm.
Ok, let’s agree on one thing right here, right now: everything in Ruby is an object. No matter how crazy it’s about to get, just remember that. In fact, it’s worth repeating again: Everything in Ruby is an object – even a class.
Got it? Okay, now let’s figure what the hell that code means, exactly.
Class Methods, Because Your Instances Should Never Be Too Greedy
In order to understand the meaning behind
class << self, we first need to understand the
<< self syntax. Let’s recap a couple basics about class inheritance first:
- Classes can have two different types of methods: class methods, which can be called on a
Classobject, and instance methods, which can only be called on instances of a
- There are multiple ways to create class methods:
You can use
self as the receiver of a method within a class, which is probably the most common way of defining a class method:
1 2 3 4 5
You can also define a method on the class name (for example, class
Book), which implies that the entire
Class Book object can receive the
1 2 3
But, you can also do this:
1 2 3 4 5
And – wait for it – this:
1 2 3 4 5 6 7
Okay, so that funky
class << self syntax is just another way of defining a class method? But…but how?
One Method To Rule Them All
So, we know that class methods are a good place to put all the behavior and functionality of all instances of that class. If you want all instances of your
Book objects to have a title and an author, you’d want that behavior to be put into the
Book class, since all instances of Book will inherit from their parent class.
But, what if you wanted a particular instance of a
Book to have a specific kind of functionality. Well, you definitely wouldn’t want to define a method on the class, because it’s only a particular instance that you care about. So why not define a method on that particular instance, then?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
At first glance, nothing here seems all that weird, right? Both the books have access to the
type class method, which we defined earlier, while only the
Book object has access to the
wilbur method. Ruby seems to know that the
wilbur method is scoped only to this instance, but it also knows that this instance has other methods – class methods – that are also accessible to it. But how is this actually possible?
Well, the answer is for two reasons: singleton methods and Ruby’s method lookup chain.
Singleton methods are methods defined on an object itself, rather than on an object’s class. Ruby’s method lookup chain is pretty intricate:
An object inherits from its class, and its class can inherit from many more objects, which will then inherit from
Object, which inherits from the great grandma of all objects in Ruby:
BasicObject. Remember: everything in Ruby is an object – even a class.
So at this point, you’re probably wondering what this has to do with class methods. Well, a lot, actually.
A Class Of One’s Own
We can create all the singleton methods we want, but where do they all go? Not in the
Book class, that’s for sure. So where do we put them, exactly?
It turns out, an object’s singleton methods all go into their own neat little class called an eigenclass, which is just another name for a singleton class. The word “eigen” comes from a German term meaning “one’s very own”. I personally like to call it an eigenclass because it minimizes confusion between singleton methods and classes. Also, throwing down terms like eigenclass make you sound like a total badass.
Here’s the cool thing about eigenclasses: they’re totally hidden. I should warn you though, the thing that makes them cool is the very same thing that makes them complicated. Because they’re hidden and anonymous, you obviously can’t see them and so it’s hard to figure out where in the method lookup path they are. Here’s the trick, though: whenever you open up an eigenclass, you shift up the original class.
In my book example, the
charlottes_web object inherits from the
Book class. But when I created the
wilbur method, I opened up the object’s eigenclass, and shifted up the original
Book class. Now, the
charlottes_web object inherits from its eigenclass, which in turn inherits from the
Book class. The
Book class has now become the superclass of our object.
Okay, that was a lot. To recap, here’s the most important stuff to know about the mysterious eigenclass:
- An eigenclass is an anonymous class that is created to hold an object’s singleton methods.
- The anonymous eigenclass then becomes the object’s immediate class, which it inherits from.
- The original class is re-designated as the superclass of the anonymous eigenclass.
- But because eigenclasses are hidden, when you call
charlottes_web.class, it will return
Reveal Thyself, You Eigen, You!
So, eigenclasses don’t show themselves. Cool. Except not cool. Because I want to see it! Well, you can see it, but you have to do a little extra work to make the magic happen. Actually, all you have to do is add a method available to all Ruby
Objects, like this:
1 2 3 4 5 6 7 8 9 10 11 12 13
We open up the eigenclass of the object when we use the
class << self syntax. And once we open it up, we are in the scope of the eigenclass. Here,
self is now the eigenclass object (everything in Ruby is an object!), and since we are returning
self, we will get to see what the eigenclass actually looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Interesting. So, the eigenclass of our
charlottes_web object does look pretty anonymous, and you might not even notice its weirdness at first. But, it does clearly seem to be a
Class object and, as we expected, was inserted into the method lookup chain right between the object and the
But if you look at the last two lines and their value, that’s where stuff gets really interesting. The
wilbur method, which we defined on a particular instance of an object, is a singleton method on only that object. The
type method, however, lives in the eigenclass of that object.
Is it all coming together now? While the
wilbur method could only be called on an instance, the
type method can be called on an entire class. So, perhaps you’re not not technically creating a class method, but more of an “eigenclass class method”. In fact, there actually is no such thing as a “class method” – you’re actually inside of the eigenclass when you create that. But effectively, it’s the same thing, because you can’t see an eigenclass and it still inherits all the methods from a basic
If all of this was Greek to you, don’t worry. This is just honestly really hard stuff. At the end of the day, all you really need to know is that
class << self is just another way of defining a class method. That and, everything in Ruby is an object.
There’s plenty of debate about whether or not using the
class << self syntax is helpful or just confusing. Personally, I like to use it when I have a lot of class methods to define. It can keep your code clean and easy to read, and helps you avoid typing out
self.method multiple times.
But, if DRYing out your code is more confusing to you than helpful, you should probably avoid it. It’s more about personal preference than anything else. Find a style that works for you and try not to think too much about all the crazy anonymous classes spinning around your head. Try being the keyword here.
- Technically speaking, there’s actually no such thing as a class method in Ruby. You’re always opening up the eigenclass/singleton class of an object whenever you define a class method. Keep in mind that there are many different syntaxes you can use in order to achieve this!
- Curious about the
class << selfdebate? Check out this thread on Stack Overflow.
- Read more about the method lookup path to understand where Ruby looks for stuff.
- Tons of good resources on this stuff here and here. Oh, and here.