Mark J. Reed
11/30/2003 3:24:00 AM
On Sun, Nov 30, 2003 at 01:59:54PM +1100, Greg McIntyre wrote:
> I know "class << x" does, but can somebody explain to me the rationale
> behind the syntax?
First: classes in Ruby are objects, just like everything
else. In particular, they are objects of the class named Class
(which is an instance of itself!). There's nothing magical about
them; in particular, a class is a *value*. Now, the usual way of
creating a class ("class Name") happens to simultaneously create
a constant (in this case Name) referring to the created class,
but that's not the only way of creating a class. You can, in fact,
create anonymous classes, and one way of doing that is via "class
<< object".
What "class << object" does is create a new, unnamed class and make
that class the new class of "object", putting it in between the instance
and its original class. It does this transparently; for instance,
calling "class" on the object still reports the original class, because
the class method is written to skip over anonymous classes.
The upshot is that you can define methods on an object without defining
them for all objects of that class. For instance:
irb(main):001:0> greeting = "Hello"
=> "Hello"
irb(main):002:0> class << greeting
irb(main):003:1> def greet(x="World")
irb(main):004:2> puts "#{self}, #{x}!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> greeting.greet
Hello, World!
=> nil
irb(main):008:0> "Hello".greet
NoMethodError: undefined method `greet' for "Hello":String
from (irb):8
Note that the method is associated with the value, not the variable you
use to access it:
irb(main):009:0> yo=greeting
=> "Hello"
irb(main):010:0> yo.greet
Hello, World!
irb(main):011:0> greeting="Hi"
=> "Hi"
irb(main):012:0> greeting.greet
NoMethodError: undefined method `greet' for "Hi":String
from (irb):12
So, what happens when the object on the right of the "<<" is a class?
Exactly the same thing! It gives you the ability to define methods on
that class (which is, again, just another object) without having to
define them for all objects of its class (which is Class). If you
defined a method of Class it would be available on all classes in
Ruby; 'new' is such a method, for instance.
-Mark