On Sat, May 16, 2009 at 1:24 AM, Gary Wright <gwtmp01 / mac.com> wrote:
>
> On May 15, 2009, at 7:46 AM, Joshua Ballanco wrote:
>>>
>>> Right. So then the question: is there a compelling reason that they
>>> should be allowed to be subclassed? (I mean, other than the obvious:
>>> "Because that's not the way Ruby was designed" answer.) I cannot come up
>>> with any compelling technical reason why the artificial limitation of being
>>> unable to subclass "virtual classes"[1] should exist.
>
> The purpose of an eigenclass is to hold per object methods.  ¨Βσυγθτθες> is always always a one-to-one relationship between an eigenclass and its
> "eigeninstance" (sorry, but I can't think of a clearer term at the moment).
>
> The idea of subclassing an eigenclass contradicts that one-to-one
> relationship.  ¨Βωογουμσυβγμασσ αξ ειηεξγμασστθεςχουμβε ξο χατο
> cause ruby to search the new subclass for instance methods since it wouldn't
> have a matching eigeninstance (sorry, again).  ¨Βχουμξοβε ιξ τθνετθοδ
> lookup chain of any object.
>
> Just to be complete, I'll point out that there is a way for eigenclasses to
> have a subclass and that is when the eigeninstances are themselves classes.
>  ¨Βθιισ νοστ γμεαιξ ±®Ή®  ¨Βισ συβγμασσ οζ Α¬ τθεξ Β®ειηεξγμασσ χιμμ
> be a subclass of A.eigenclass.  ¨Βφειξ τθισ γασε αξθαφε το εψισ> before their eigenclasses can be accessed and not the other way around.

And there, IMHO, is where things break down.  If the definition of an
eigenclass is a 'class' which holds per object methods, then the class
of a class which has subclasses is not an eigenclass since it provides
methods not only to it's sole instance but also to it's instance's
subclass(es).

That's why I prefer to think of the objects which serve as the class
of a class as metaclasses, which is in line with the terminology used
in several other languages.

This whole area of Ruby reminds me a bit of Plato's cave, we see
images on the wall cast by "smoke" and "mirrors" in the
implementation, and try to name them. And the smoke has been shifting
a bit and the mirrors have been moving slightly. When you step outside
of the cave and look at the implementation you find:

There's a flag called FL_SINGLETON which when set in the header of a
class object means:


   * It will get cloned if you clone its instance
   * You can't copy it.
    * You can't make a subclass of it, unless you are ruby itself
creating a subclass in which case
     subclasses of the "singleton" metaclass are created under the covers.
   * It will be bypassed by the Object#class method
   * It will be filtered out of the results Module#ancestors method
   * It will be skipped in the search for methods by
Module#instance_methods and it's related methods
  * Its methods are considered singleton methods
  * It has a hidden 'class' instance variable __attached__ which
points to it's sole instance
  * Its skipped over by ObjectSpace.each_object, so
ObjectSpace.each_object(Class) won't yield it.
  * It will prevent dumping by Marshall.dump

So what exactly does the singleton in FL_SINGLETON mean.  Well, it
does mean that a class marked with FL_SINGLETON has only one direct
instance. It doesn't mean in the case of a singleton class which
happens to be a metaclass that it doesn't have subclasses, just that
you as a Ruby programmer can only create or add to its subclasses by
subclassing its attached class.

And while you might think that singleton method was a synonym for
instance specific method, once again this is only true when it's a
singleton method within an instance-specific singleton class.

class Foo
    def self.blat
        :blat
    end
end

class Bar < Foo
end

Foo.singleton_methods => [:blat]
Bar.singleton_methods => [:blat]

The 2nd ed of the Pickaxe used the term "virtual class" and seems to
call the FL_SINGLETON bit the 'V' bit.  Looking at Ruby 1.8.6, the
term virtual class only appears in errors raised when you try to
   1. Try to make a subclass of a class marked with FL_SINGLETON and
you'll get the error
"can't make subclass of virtual class"
   2. Try to add a singleton method to an instance of an immediate
class (e.g. a Fixnum), since there's no klass ptr so nowhere to insert
the needed instance specific class in the lookup chain, and you'll get
the error "no virtual class for %s"
   3. Try to instantiate an instance of a class marked with
FL_SINGLETON and you'll get the error can't create instance of virtual
class"

And in Ruby 1.9, these error descriptions have all be changed to
remove the usage of "virtual class" and replace it with "singleton
class".

I kind of wish that FL_SINGLETON had actually been named FL_VIRTUAL,
or FL_HIDDEN, since what the flag does mostly is to hide such classes
in the standard library provided API. (ignoring the leak from class <
a;self;end

Back in the mists of Ruby history, it became popular to call any class
marked with FL_SINGLETON as a metaclass, probably because that's what
_why named the leak method in the Poignant Guide.

That added another layer of confusion, because to many of us metaclass
means the class of a class, and an instance-specific class ain't a
metaclass, it's a class whether it's hidden or not.

And I think that that's where the name eigenclass got coined, as an
alternative to singleton class, for better or worse.  And with the
publication of "The Ruby Programming Language" it's gotten a bit of a
blessing from Matz, although the Ruby 1.9 implementation uses
singleton class in those errors where virtual class was used before.

I personally think that the distinction between metaclasses (in the
generally accepted sense of the class of a class) and
instance-specific classes is more important than the accidental
similarities between singleton classes used as instance-specific
classes and singleton-classes used as metaclasses.

And I guess eigenclass is not a bad term to use for a class which
provides behavior to a single instance, i.e. an instance-specific
class, but I don't like it as a term for a metaclass.

But that's just me, after all it's all just images caused by smoke and
mirrors <G>

-- 
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale