meta-class subclass relationships

G

Greg Weeks

Ruby exposes its singleton meta-classes, eg:

class <<B ; $Meta_B = self ; end

But their relationships are not quite what I expected. For example:

Suppose that A inherits from B (and B inherits from Object). Of course,
this means that A instances respond to all the B instance messages. So:

A.new.is_a? B -> true

At the same time, the A class object responds to all the B class object
messages. So:

class <<Object ; $Meta_Object = self ; end
class <<B ; $Meta_B = self ; end
class <<A ; $Meta_A = self ; end

A.is_a? $Meta_A -> true
B.is_a? $Meta_A -> false
A.is_a? $Meta_B -> true
B.is_a? $Meta_B -> true

Since everything that is_a $Meta_A also is_a $Meta_B, I expected a
subclass/superclass relationship. Indeed, I expected the following to
be true:

$Meta_A.superclass == $Meta_B
$Meta_B.superclass == $Meta_Object
$Meta_Object.superclass == Class
Class.superclass == Module
Module.superclass == Object
Object.superclass == nil

The above superclass chain reflects how a message to the class A object
is looked up. What surprised me is that the first two equalities above
are false.

Should they have been true?

FWIW: The superclass of both $Meta_A and $Meta_B is something called
#<Class:Class>, which is its own superclass and is a subclass of
$Meta_Object:

$X = $Meta_A.superclass -> #<Class:Class>
$X == $Meta_B.superclass -> true
$X == $X.superclass -> true
$X < $Meta_Object -> true
 
G

Greg Weeks

PS: I just realized that my (erroneous) expectation

$Meta_A.superclass == $Meta_B
$Meta_B.superclass == $Meta_Object

is asserted in Figure 24.2 of the Pickaxe book (2nd edition). Eg, for
the second equality, just replace "Guitar" with "B". So why, I wonder,
isn't it true?
 
R

Robert Dober

Hmm seems consistent for me, although the model you expect should have
some merits, I believe Smalltalk satisfies your expectations....
However there are no metaclasses in ruby, only singleton classes,
naming is important here to emphasis on the difference in behavior.

635/135 > irb
irb(main):001:0> a = Class::new
=> #<Class:0xb7d89750>
irb(main):002:0> ma = class << a; self end
=> #<Class:#<Class:0xb7d89750>>
irb(main):003:0> b = Class::new a
=> #<Class:0xb7d77500>
irb(main):004:0> mb = class << b; self end
=> #<Class:#<Class:0xb7d77500>>
irb(main):005:0> b < a
=> true
irb(main):006:0> mb < ma
=> nil
irb(main):007:0> mb.superclass
=> #<Class:Class>
irb(main):008:0> ma.send :define_method, :a do 42 end
=> #<Proc:0xb7d56724@(irb):8>
irb(main):009:0> ma.a
NoMethodError: undefined method `a' for #<Class:#<Class:0xb7d89750>>
from (irb):9
from :0

Stupid me, of course I defined a method for a

irb(main):010:0> a.a
=> 42
irb(main):011:0> b.a
=> 42
which works for b too, as b < a

irb(main):012:0> mma = class << ma; self end
=> #<Class:#<Class:#<Class:0xb7d89750>>>
irb(main):013:0> mmb = class << mb; self end
=> #<Class:#<Class:#<Class:0xb7d77500>>>
irb(main):014:0> mma.send :define_method, :ma do 42 end
=> #<Proc:0xb7d3e228@(irb):14>
irb(main):015:0> ma.ma
=> 42
Now this was for ma
irb(main):016:0> mb.ma
NoMethodError: undefined method `ma' for #<Class:#<Class:0xb7d77500>>
from (irb):16
from :0
and as mb < ma does not hold this makes sense.

BTW meta caught me I should have called the guys above sa, sb, ssa and ssb :(

Interesting that the Pickaxe got this wrong, never publish code you
have not run ;), or maybe this changed between 1.6 and 1.8?

Cheers
Robert
 
P

pluskid

FWIW: The superclass of both $Meta_A and $Meta_B is something called
#<Class:Class>, which is its own superclass and is a subclass of
$Meta_Object:

$X = $Meta_A.superclass -> #<Class:Class>
$X == $Meta_B.superclass -> true
$X == $X.superclass -> true
$X < $Meta_Object -> true

In fact, currently in ruby:

A.metaclass.superclass == A.class.metaclass

if you define metaclass as :

class Object
def metaclass; class << self; self; end; end
end

That's why you see "$Meta_A.superclass -> #<Class:Class>". Maybe it
is not very useful. But it is the case now. And here are some links if
you are interested in:

* http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
* http://practicalruby.blogspot.com/2007/02/ruby-metaprogramming-introduction.html
 
D

David A. Black

Hi --

PS: I just realized that my (erroneous) expectation

$Meta_A.superclass == $Meta_B
$Meta_B.superclass == $Meta_Object

is asserted in Figure 24.2 of the Pickaxe book (2nd edition). Eg, for
the second equality, just replace "Guitar" with "B". So why, I wonder,
isn't it true?

It will be :) It worked in 1.8.2, doesn't work in 1.8.6, works again
in 1.9. I don't know what the rationale was for changing the model,
but it's changed back.

rubypal:~$ cat super.rb
class Object
def singleton_class
class << self; self; end
end
end
p String.singleton_class.superclass == Object.singleton_class

rubypal:~$ /usr/local/lib/ruby-1.8.2/bin/ruby -v super.rb
ruby 1.8.2 (2004-12-25) [i686-linux]
true
rubypal:~$ ruby -v super.rb
ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux]
false
rubypal:~$ /usr/local/lib/ruby-svn/bin/ruby -v super.rb
ruby 1.9.0 (2007-11-07 patchlevel 0) [i686-linux]
true


David
 
D

David A. Black

Hi --

Interesting that the Pickaxe got this wrong, never publish code you
have not run ;), or maybe this changed between 1.6 and 1.8?

It changed between 1.8.2 and 1.8.6 -- see my last response in this
thread.


David
 
G

Greg Weeks

*Many* thanks for the info. I was going to swallow the 1.8.6 behavior,
but I much prefer the Figure 24.2 behavior.

On the other hand, it is not true that A.class == $Meta_A. For the
"class" message, the rule seems to be that you follow the inheritance
chain until you find a non-virtual class. This would be a reasonable
behavior for the "superclass" message too, I think. (Preferable,
perhaps.)

As for "Meta": I don't know if the English language is precise on this
point. As I understand it, a meta-foo is a foo *about* foos. A
meta-class is a class with class instances, I would think. Although
most Ruby meta-classes are virtual, we can still mix modules into them,
so they provide a powerful mechanism for meta-programming. That's why
I'm inclined to call them (limited) meta-classes.
 
D

David A. Black

Hi --

*Many* thanks for the info. I was going to swallow the 1.8.6 behavior,
but I much prefer the Figure 24.2 behavior.

On the other hand, it is not true that A.class == $Meta_A. For the
"class" message, the rule seems to be that you follow the inheritance
chain until you find a non-virtual class. This would be a reasonable
behavior for the "superclass" message too, I think. (Preferable,
perhaps.)

As for "Meta": I don't know if the English language is precise on this
point. As I understand it, a meta-foo is a foo *about* foos. A
meta-class is a class with class instances, I would think. Although
most Ruby meta-classes are virtual, we can still mix modules into them,
so they provide a powerful mechanism for meta-programming. That's why
I'm inclined to call them (limited) meta-classes.

I believe Jim Weirich once said that the only real metaclass in Ruby
is Class, since it's the source of class instances.


David
 
G

Greg Weeks

I believe Jim Weirich once said that the only real metaclass in Ruby
is Class, since it's the source of class instances.

True if "real" means "non-virtual", as it so often does. But that
leaves
virtual metaclasses, at the heart of Ruby metaprogramming.
 
D

David A. Black

Hi --

True if "real" means "non-virtual", as it so often does. But that
leaves
virtual metaclasses, at the heart of Ruby metaprogramming.

I'm not sure in what sense they're virtual (though I know that
terminology occurs in some error messages). Once they're created, they
exist as first-class objects.


David
 
R

Rick DeNatale

Hi --




I believe Jim Weirich once said that the only real metaclass in Ruby
is Class, since it's the source of class instances.

In Smalltalk, where this stuff isn't so hidden. a metaclass is a class
of a class.

The main layout of classes and singleton classes as a parallel
hierarchy with a cross-over and a loop at the top in Ruby is
remarkably similar to that of Smalltalk. Of course Smalltalk also
doesn't interpose module proxies as class-like things marked to be
special, since it doesn't have modules.

On the other hand Ruby doesn't have a Metaclass class like Smalltalk
does. Smalltalk metaclasses have behavior mostly for interacting with
the IDE. Sometimes I wish that Matz had put in a Metaclass class just
so things wouldn't be so damned mysterious.

IIRC the quote from Matz in the Pickaxe was that these things we are
talking about "act just like" Smalltalk Metaclasses, but they aren't
metaclasses, they are singleton classes of classes. I don't know if
it's how Matz intended it, but I can interpret it as meaning that they
aren't metaclasses just because there isn't a Metaclass class. In any
event, I haven't found much interference from knowing how Smalltalk
classes and metaclasses interact in understanding Ruby.
 
W

_why

As for "Meta": I don't know if the English language is precise on this
point. As I understand it, a meta-foo is a foo *about* foos. A
meta-class is a class with class instances, I would think. Although
most Ruby meta-classes are virtual, we can still mix modules into them,
so they provide a powerful mechanism for meta-programming. That's why
I'm inclined to call them (limited) meta-classes.

Totally, I always think of meta- as meaning "once removed" in a
parallel fashion more than a compound fashion, you know? Rather than
strictly saying a "class about classes," I think it's also kind of
a magnetic lasso around "classes informed about classes" or "an
annex to a class."

I guess metadata is straightforwardly "data about data," but data is
a simple term. Class has complexities (definitions as well as
storage space) which give ambiguity to the meta- part I think.

Anyway, if you look at the use of the term on the web, like in
naming sites, such as metafilter or metacritic: I don't think it is
implied that these sites would be "filters about filters" or
"critics criticizing other critics," but simply that they are once
removed, culling information from other sites of a similar nature,
operating in parallel rather than compoundly. I don't know, I'm
just trying to give some other evidence of how elastic that little
prefix can be.

Maybe such things would be better suited with a super- but I like
both English and Ruby for the ways you have a bit of... errr...
poetic license, I guess.

_why
 
G

Greg Weeks

True if "real" means "non-virtual", as it so often does. But that
I'm not sure in what sense they're virtual (though I know that
terminology occurs in some error messages). Once they're created, they
exist as first-class objects.

Right. But they can't be instantiated, and they are specially handled
by various reflection methods (eg, #class completely ignores them). The
term "virtual" didn't appeal to me much either, but Pickaxe and the
error messages both use it.
 
R

Rick DeNatale

Right. But they can't be instantiated,

Well, actually they each have one instance, which is created at the
same time they are (or vice-versa).

This is the sense that they are 'singletons'.

And I can think of at least three other classes which have single
instances and can't be 'further' instantiated, although I've never
heard NilClass, TrueClass, and FalseClass referred to as singleton
classes.
and they are specially handled
by various reflection methods (eg, #class completely ignores them).

And superclass seems unsure about them from release to release.
The
term "virtual" didn't appeal to me much either, but Pickaxe and the
error messages both use it.

Right, as far as I can see it only comes up in the error messages when
you try to subclass a class which has the FL_SINGLETON flag bit set.
 
R

ruby-talk

Maybe such things would be better suited with a super- but I like
both English and Ruby for the ways you have a bit of... errr...
poetic license, I guess.

Meta is a prefix of Greek origin[1]. The Latin would be ``post'', which
leads me to two thoughts.

* A ruby metaclass really is like a postclass, which is pretty neat.

* We're overusing prefixes like meta when so many options exist, such as
postclass, or what about panclass, hypoclass, or epiclass[2]? I know,
there's eigenclass, but does that really clarify it for anyone?

Metaclass is already embedded in the culture, but I nonetheless
find this to be a useful way to reason about the concept and how it fits
into the language.


[1] http://en.wikipedia.org/wiki/Meta
[2] http://en.wikipedia.org/wiki/English_prefixes
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top