Книга: Metaprogramming Ruby 2
Назад: Singleton Methods
Дальше: Quiz: Module Trouble

Singleton Classes

Where you place the final piece in the object model puzzle.

Singleton classes are the UFOs of the Ruby world: even if you never see one in person, you can find scattered hints of their existence all over the place. Let’s start our investigation into this difficult subject by collecting some evidence. (Be aware that the next few pages contain advanced material that might take a while for you to digest. If you want, you can skip straight to , on your first read through and come back to this section later.)

The Mystery of Singleton Methods

In , you learned how Ruby finds methods by going right into the receiver’s class and then up the class hierarchy. For example:

 
class​ MyClass
 
def​ my_method; ​end
 
end
 
 
obj = MyClass.new
 
obj.my_method

Bill draws the following flowchart and says, “When you call my_method, Ruby goes right into MyClass and finds the method there.” So far, so good.

images/chp4_object_lookup.jpg

Now, what happens if you define a Singleton Method () on obj?

 
def​ obj.my_singleton_method; ​end

If you look at the previous flowchart, you’ll notice that there’s no obvious home for my_singleton_method there.

The Singleton Method can’t live in obj, because obj is not a class. It can’t live in MyClass, because if it did, all instances of MyClass would share it. And it cannot be an instance method of MyClass’s superclass, Object. So then, where do Singleton Methods live?

Class methods are a special kind of Singleton Method—and just as baffling:

 
def​ MyClass.my_class_method; ​end

If you look at the following figure, you’ll find that, again, my_class_method doesn’t seem to live anywhere in Bill’s diagram.

images/chp4_class_lookup.jpg

The explanation of this mystery could surprise you.

Singleton Classes Revealed

When you ask an object for its class, Ruby doesn’t always tell you the whole truth. Instead of the class that you see, an object can have its own special, hidden class. That’s called the singleton class of the object. (You can also hear it called the metaclass or the eigenclass. However, “singleton class” is the official name.)

Methods like Object#class keep the singleton class carefully hidden, but you can work around them. Ruby has a special syntax, based on the class keyword, that places you in the scope of the singleton class:

 
class​ << an_object
 
# your code here
 
end

If you want to get a reference to the singleton class, you can return self out of the scope:

 
obj = Object.new
 
 
singleton_class = ​class​ << obj
 
self
 
end
 
 
singleton_class.class ​# => Class

That sneaky singleton class was trying to hide, but we managed to find it.

Back in Ruby’s old days, you had to return self like we just did to get a reference to the singleton class. These days you can also get a reference to the singleton class with the handy Object#singleton_class method:

 
"abc"​.singleton_class ​# => #<Class:#<String:0x331df0>>

The previous example also shows that a singleton class is a class—but a very special one. For starters, it’s invisible until you resort to either Object#singleton_class, or the exotic class << syntax. Also, singleton classes have only a single instance (that’s where their name comes from), and they can’t be inherited. More important, a singleton class is where an object’s Singleton Methods live:

 
def​ obj.my_singleton_method; ​end
 
singleton_class.instance_methods.grep(/my_/) ​# => [:my_singleton_method]

To fully understand the consequences of this last point, you have to look deeper into Ruby’s object model.

Method Lookup Revisited

In , you learned about the Ruby object model and method lookup. Back then, we had to leave some parts of the object model unexplored. Singleton classes are the missing link we needed. Once you understand singleton classes, all the bits and pieces in the object model finally fall into place.

Method Lookup Review

To look into the object model, you need a practical example to focus on. Let’s write a “lab rat” program:

 
class​ C
 
def​ a_method
 
'C#a_method()'
 
end
 
end
 
 
class​ D < C; ​end
 
 
obj = D.new
 
obj.a_method ​# => "C#a_method()"

If you draw a picture of obj and its ancestors chain, it will probably look like the following figure. (For now, you don’t have to bother with singleton classes or modules.)

images/chp4_lookup_simple.jpg

You know that method lookup goes one step to the right, then up. When you call obj.a_method(), Ruby goes right into obj’s class D. From there, it climbs up the ancestors chain until it finds a_method in class C. Now, let’s add singleton classes to the mix.

Singleton Classes and Method Lookup

As you explore singleton classes, you may notice that their names are not meant to be uttered by humans. When you print it on the screen, a singleton class looks something like this:

 
obj = Object.new
 
obj.singleton_class ​# => #<Class:#<Object:0x007fd96909b588>>

The diagrams in the rest of this chapter identify singleton classes with a simple # prefix. By this convention, #obj is the singleton class of obj, #C is the singleton class of C, and so on.

Armed with the singleton_class method and your new naming convention, you can now proceed with your fearless exploration of the object model. Let’s go back to the “lab rat” program and define a Singleton Method ().

 
class​ << obj
 
def​ a_singleton_method
 
'obj#a_singleton_method()'
 
end
 
end

Now for an experiment. You know that a singleton class is a class, so it must have a superclass. Which is the superclass of the singleton class?

 
obj.singleton_class.superclass ​# => D

The superclass of obj’s singleton class is D. Try adding this newfound knowledge to the diagram of the “lab rat” object model. The result is shown in Figure 7, .

images/chp4_lookup_eigen.jpg

Figure 7. Method lookup with singleton classes

You can see how Singleton Methods fit into the normal process of method lookup. If an object has a singleton class, Ruby starts looking for methods in the singleton class rather than the conventional class, and that’s why you can call Singleton Methods such as obj#a_singleton_method. If Ruby can’t find the method in the singleton class, then it goes up the ancestors chain, ending in the superclass of the singleton class—which is the object’s class. From there, everything is business as usual.

Now you understand how Singleton Methods work. But what about class methods? Yes, they’re just a special case of Singleton Methods, but they deserve a closer look.

Singleton Classes and Inheritance

In this section, we’re going to look at the connections between classes, singleton classes, and superclasses. This area of the object model can be a real brain-twister. Once it clicks in your mind, however, it will feel elegant and beautiful. If you’re stuck, just look at the pictures or fire up irb and experiment on your own.

Try adding a class method to the “lab rat” program.

 
class​ C
 
class​ << self
 
def​ a_class_method
 
'C.a_class_method()'
 
end
 
end
 
end

Now you can explore the resulting object model. (As you do that, keep in mind that singleton classes became slightly more visible in Ruby 2.1. Starting from that version, if you ask a singleton class for its ancestors, the result will include ancestors that are themselves singleton classes. Until Ruby 2.0, ancestors always shows regular classes only.)

 
C.singleton_class ​# => #<Class:C>
 
D.singleton_class ​# => #<Class:D>
 
D.singleton_class.superclass ​# => #<Class:C>
 
C.singleton_class.superclass ​# => #<Class:Object>

Bill grabs a scrap of paper and draws the following diagram.

images/chp4_lookup_inheritance.jpg

Figure 8. Singleton classes and inheritance

This is a somewhat complicated diagram. The arrows marked with S link classes to their superclasses, and the arrows marked with C link objects (including classes) to their classes, which in this case are all singleton classes. The arrows marked with a C do not point at the same classes that the class method would return, because the class method doesn’t know about singleton classes. For example, obj.class would return D, even if the class of obj is actually its singleton class, #obj.

This diagram doesn’t include modules. If you’re a completist, you can draw the Kernel module between Object and BasicObject. On the other hand, you probably don’t want to include #Kernel in this diagram. Although modules can have singleton classes like any other object, the singleton class of Kernel is not part of obj’s or #D’s ancestor chains.

Apparently, Ruby organizes classes, singleton classes, and superclasses in a very purposeful pattern. The superclass of #D is #C, which is also the singleton class of C. By the same rule, the superclass of #C is #Object. Bill tries to sum it all up, making things even more confusing: “The superclass of the singleton class is the singleton class of the superclass. It’s easy.”

This complicated arrangement of classes, superclasses, and singleton classes can be baffling. Why does Ruby go to such lengths to organize the object model this way? The reason is that thanks to this arrangement, you can call a class method on a subclass:

 
D.a_class_method ​# => "C.a_class_method()"

Even if a_class_method is defined on C, you can also call it on D. This is probably what you expect, but it’s only possible because method lookup starts in #D and goes up to #D’s superclass #C, where it finds the method.

Ingenious, isn’t it? Now you can finally grasp the entire object model.

The Great Unified Theory

“The Ruby object model is a beautiful place,” Bill notes, with a dreamy expression on his face. “There are classes, singleton classes, and modules. There are instance methods, class methods, and Singleton Methods.”

At first glance, it all looks very complex. Look closer, and the complexity fades away. If you put singleton classes together with regular classes and modules, you end up with the seven rules of the Ruby object model:

  1. There is only one kind of object—be it a regular object or a module.

  2. There is only one kind of module—be it a regular module, a class, or a singleton class.

  3. There is only one kind of method, and it lives in a module—most often in a class.

  4. Every object, classes included, has its own “real class,” be it a regular class or a singleton class.

  5. Every class, with the exception of BasicObject, has exactly one ancestor—either a superclass or a module. This means you have a single chain of ancestors from any class up to BasicObject.

  6. The superclass of the singleton class of an object is the object’s class. The superclass of the singleton class of a class is the singleton class of the class’s superclass. (Try repeating that three times, fast. Then look back at Figure 8, , and it will all make sense.)

  7. When you call a method, Ruby goes “right” in the receiver’s real class and then “up” the ancestors chain. That’s all there is to know about the way Ruby finds methods.

Any Ruby programmer can stumble on a difficult question about the object model. “Which method in this complicated hierarchy gets called first?” Or maybe, “Can I call this method from that object?” When this happens to you, review the seven rules listed earlier, maybe draw a quick diagram of the object model, and you’ll find the answer in no time at all.

Congratulations—you now understand the entire Ruby object model.

Class Methods Syntaxes

Because class methods are just Singleton Methods that live in the class’s singleton class, now you have three different ways to define a class method. They’re shown in the following code.

 
def​ MyClass.a_class_method; ​end
 
 
class​ MyClass
 
def​ self.another_class_method; ​end
 
end
 
 
class​ MyClass
 
class​ << self
 
def​ yet_another_class_method; ​end
 
end
 
end

The first syntax is usually frowned upon by expert Rubyists because it duplicates the class name, making it more difficult to refactor. The second syntax takes advantage of the fact that self in the class definition is the class itself. The third syntax is the trickiest one: the code opens the singleton class and defines the method in there. This last syntax acknowledges the singleton class explicitly, so it will win you some street cred in Ruby circles.

Singleton Classes and instance_eval()

Now that you know about singleton classes, you can also fill in one missing snippet of knowledge about the instance_eval method. In , you learned that instance_eval changes self, and class_eval changes both self and the current class. However, instance_eval also changes the current class; it changes it to the singleton class of the receiver. This example uses instance_eval to define a Singleton Method ():

 
s1, s2 = ​"abc"​, ​"def"
 
 
s1.instance_eval ​do
 
def​ swoosh!; reverse; ​end
 
end
 
 
s1.swoosh! ​# => "cba"
 
s2.respond_to?(:swoosh!) ​# => false

You’ll rarely, if ever, see instance_eval used purposefully to change the current class, as in the example above. The standard meaning of instance_eval is this: “I want to change self.”

Class Attributes

Bill’s detailed explanations have left you a bit perplexed. “Okay,” you say, “I can see how singleton classes are useful to understanding the object model. But how do I use them in practice?”

Let’s look at an example involving Class Macros (). Do you remember the attr_accessor method from ? It generates attributes for any object:

 
class​ MyClass
 
attr_accessor :a
 
end
 
 
obj = MyClass.new
 
obj.a = 2
 
obj.a ​# => 2

But what if you want to define an attribute on a class instead? You might be tempted to reopen Class and define the attribute there:

 
class​ MyClass; ​end
 
 
class​ Class
 
attr_accessor :b
 
end
 
 
MyClass.b = 42
 
MyClass.b ​# => 42

This works, but it adds the attribute to all classes. If you want an attribute that’s specific to MyClass, you need a different technique. Define the attribute in the singleton class:

 
class​ MyClass
 
class​ << self
 
attr_accessor :c
 
end
 
end
 
 
MyClass.c = ​'It works!'
 
MyClass.c ​# => "It works!"

To understand how this works, remember that an attribute is actually a pair of methods. If you define those methods in the singleton class, they become class methods, as if you’d written this:

 
def​ MyClass.c=(value)
 
@c = value
 
end
 
 
def​ MyClass.c
 
@c
 
end

As usual, Bill grabs the nearest available scrap of paper and scribbles the following diagram on it. “That’s how you define an attribute on a class,” he says.

images/chp4_class_attributes.jpg

Figure 9. Class attributes live in the class’s singleton class.

You can also see another interesting detail in this diagram. The superclass of #BasicObject is none other than good old Class. This fact explains why you can call MyClass.b and MyClass.b=.

Clearly happy with his own explanation, Bill leans back in his comfy chair. “Cool stuff, huh? Now, let’s try a little quiz.”

Назад: Singleton Methods
Дальше: Quiz: Module Trouble