Thanks for sharing the eigenclass hack.

More interestingly though, is where does the new method comes from when doing A.new. We believe that once we've looked at all of the ancestor classes' eigenclasses for new, that we then hit the Class and Module classes in the list of eigenclasses. Does that make sense as well? It's a bit strange because you start off looking through the eigenclass hierarchy for new, and then switch to the class hierarchy at the very end for Class, Module and Object.

Is this how things are actually implemented? (BTW I'm not lazy here - we cannot look for ourselves).

Also, as long as we respect this lookup mechanism, does anyone forsee any problems in merging the identities of the eigenclass and class objects into the same object (other folks who have code that explicitly depends on the behavior of the eigenclass hack -- not sure what this really means at this time though).

Thanks,
-John




-----Original Message-----
From: MenTaLguY [mailto:mental / rydia.net]
Sent: Wednesday, March 28, 2007 1:43 PM
To: ruby-core / ruby-lang.org
Subject: Re: Virtual classes and 'real' classes -- why?

On Thu, 29 Mar 2007 04:44:16 +0900, "John Lam (CLR)" <jflam / microsoft.com> wrote:
> I was wondering if someone could help me understand why there's a parallel
> class hierarchy - there's the 'real' class objects which holds onto
> instance methods, and the 'virtual' class object that holds onto class
> methods.

Every (non-value-typed) object in Ruby has an accompanying "virtual" class, permitting "one-off" ("singleton") methods to be attached to it.  As calls to "class methods" are simply regular method calls that happen to have a class as the receiver, it was probably simplest not to make classes a special case in this regard.

These virtual classes are in fact visible to Ruby code, are most commonly referred to as "singleton classes" or (more descriptively) "eigenclasses", and can be extracted via a construct like:

 class Object
   def eigenclass
     class << self
       self
     end
   end
 end

(one would then call obj.eigenclass to get obj's eigenclass)

There is one slight difference in method lookup between class objects and other objects, though.  While for most objects, the search order could be obtained via:

 class Object
   def method_search_order
     [ self.eigenclass ] + self.class.ancestors
   end
 end

...classes also include their ancestor classes' "eigenclasses" in the search:

 class Class
   def method_search_order
     ancestors.select { |m| Class === m }.map { |c| c.eigenclass } + self.class.ancestors
   end
 end

-mental