Metaclasses

Hi, all. I’m trying to understand chapter 24 of Programming Ruby.
I’m using “metaid.rb” from why the lucky stiff’s site to help with the
examples.
(http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html)

Everything is pretty straightforward except for the diagrams of
inheritance of metaclasses. Figure 24.2 indicates that for a direct
subclass of Object, its metaclass’s superclass should be Object’s
metaclass. When I try this out in irb, I don’t get the expected
result.

$ irb -r metaid
irb(main):001:0> String.metaclass
=> #Class:String
irb(main):002:0> String.metaclass.superclass
=> #Class:Class
irb(main):003:0> String.metaclass.superclass == Object.metaclass
=> false

Surprisingly, when I try it in JRuby, I do get the expected result.

$ jirb -r metaid
irb(main):001:0> String.metaclass
=> #Class:String
irb(main):002:0> String.metaclass.superclass
=> #Class:Object
irb(main):003:0> String.metaclass.superclass == Object.metaclass
=> true

Also, figure 24.3 suggests that for an instance of String, the
metaclass should be a virtual class extending String itself.

Once again only JRuby produces the expected result.

$ irb -r metaid
irb(main):001:0> String.new.metaclass.superclass == String
=> false

$ jirb -r metaid
irb(main):001:0> String.new.metaclass.superclass == String
=> true

Something else I found weird is that when I go up the inheritance of a
String instance’s metaclass in plain ruby, I quickly run into a loop:

$ irb -r metaid
irb(main):001:0> c = String.new.metaclass.superclass.superclass
=> #Class:Class
irb(main):002:0> c == c.superclass
=> true

Any help in understanding this would be greatly appreciated!

Thanks

Neil

The JRuby discrepancies are very interesting and I don’t know the
answer. I e-mailed Charlie Nutter from JRuby and hopefully he’ll chime
in.

Something else I found weird is that when I go up the inheritance of a
String instance’s metaclass in plain ruby, I quickly run into a loop:

$ irb -r metaid
irb(main):001:0> c = String.new.metaclass.superclass.superclass
=> #Class:Class
irb(main):002:0> c == c.superclass
=> true

Any help in understanding this would be greatly appreciated!

This part at least I can explain. I think.

In metaid.rb:

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

This means that when you use this method, you’re just having the
object open up its class and return that to you. What you’re running
into isn’t really a loop so much as a fundamental particle. In the
universe it may be true that you can subdivide any particle into
smaller, “more fundamental” particles, but programming languages are
much tidier than infinity, and sooner or later you get to the first
turtle, and after that it’s turtles all the way down. (I’m assuming
you can understand me, and if you’re using _why’s guide to Ruby,
there’s a good chance I sound perfectly rational.) In real life every
turtle is made up of smaller turtles; inside a programming language,
when you hit the turtle, you’re there.

In a nutshell, I believe this means that just as the topmost class is
Object, the topmost class is a Class:Class object. If that doesn’t
help, there’s a simpler way to see it. Object is the fundamental
class; all objects are ultimately Objects. Metaclasses have a parallel
hierarchy, and all classes are ultimately instances of a Class:Class
object - the object you’ve uncovered here. In a sense you’ve
discovered the Holy Grail of the metaclass shadow world.

(I’d probably be more coherent if I hadn’t just spent about twenty
minutes reading _why’s stuff on Shoes.)


Giles B.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

Hi –

On Thu, 8 Nov 2007, Neil C. wrote:

$ irb -r metaid
irb(main):001:0> String.metaclass
=> #Class:String
irb(main):002:0> String.metaclass.superclass
=> #Class:Object
irb(main):003:0> String.metaclass.superclass == Object.metaclass
=> true

It actually depends which version of Ruby you use. The superclass
thing worked as expected in 1.8.2; then it stopped working (I’m not
sure why); and in 1.9 it’s working again. (“Not working” doesn’t mean
that the subclasses couldn’t call the methods defined in their
superclasses’ singleton classes, just that the superclass thing itself
was not in place.)

$ cat super.rb
class Object
def singleton_class
class << self; self; end
end
end

p String.singleton_class.superclass == Object.singleton_class

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

David

On 11/8/07, David A. Black [email protected] wrote:

It actually depends which version of Ruby you use. The superclass
thing worked as expected in 1.8.2; then it stopped working (I’m not
sure why); and in 1.9 it’s working again. (“Not working” doesn’t mean
that the subclasses couldn’t call the methods defined in their
superclasses’ singleton classes, just that the superclass thing itself
was not in place.)

interesting, I didn’t realize that this had changed in 1.9.

Actually, it’s not that anything isn’t in place in 1.8, it’s that the
implementation of Class#superclass skips classes in the superclass
chain, the same way that Object#class skips an instance singleton
class if there is one, and the ancestors methods replaces the wrapper
IClass nodes used to represent included modules in the behavior chain
of an object into the modules themselves in the result.

It’s smoke and mirrors, and in the case of Ruby 1.9 it seems theres a
little less smoke and mirrors in Class#superclass.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Nov 7, 8:46 pm, Neil C. [email protected] wrote:

Hi, all. I’m trying to understand chapter 24 of Programming Ruby.
I’m using “metaid.rb” from why the lucky stiff’s site to help with the
examples. (http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html)

Everything is pretty straightforward except for the diagrams of
inheritance of metaclasses. Figure 24.2 indicates that for a direct
subclass of Object, its metaclass’s superclass should be Object’s
metaclass. When I try this out in irb, I don’t get the expected
result.

Possibly this diagram will help:

On Nov 8, 2007, at 12:42 PM, Rick DeNatale wrote:

interesting, I didn’t realize that this had changed in 1.9.

Actually, it’s not that anything isn’t in place in 1.8, it’s that the
implementation of Class#superclass skips classes in the superclass
chain, the same way that Object#class skips an instance singleton
class if there is one,

Singleton classes are created on-demand behind the scenes?

– fxn

On 11/8/07, Xavier N. [email protected] wrote:

On Nov 8, 2007, at 12:42 PM, Rick DeNatale wrote:

Actually, it’s not that anything isn’t in place in 1.8, it’s that the
implementation of Class#superclass skips classes in the superclass
chain, the same way that Object#class skips an instance singleton
class if there is one,

Singleton classes are created on-demand behind the scenes?

Yes, at least in 1.8, and I can’t imagine why that would change.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hi –

On Thu, 8 Nov 2007, Rick DeNatale wrote:

Actually, it’s not that anything isn’t in place in 1.8, it’s that the
implementation of Class#superclass skips classes in the superclass
chain, the same way that Object#class skips an instance singleton
class if there is one, and the ancestors methods replaces the wrapper
IClass nodes used to represent included modules in the behavior chain
of an object into the modules themselves in the result.

By “superclass thing itself not in place” I just meant that you get
false when you ask whether C’s singleton class is the superclass of
D’s singleton class. So any documentation/books/etc. that describe it
that way will seem wrong if you try it out in 1.8.6.

It’s smoke and mirrors, and in the case of Ruby 1.9 it seems theres a
little less smoke and mirrors in Class#superclass.

Always a good sign :slight_smile:

David