Meta Meta

After watching the Pragmatic Screencasts of The Ruby Object Model and Metaprogramming with Dave Thomas a few of us at the office decided to investigate further.

Developers in the Ruby on Rails community are familiar with the concept of constructing custom finders for models.

class User
  class << self
    def find_by_geography(options)
      # ... custom geographic finder logic ...
    end
  end
end

One invokes method name find_by_geography directly from the User class.

@users = User.find_by_geography(options)

A programmer can alternately prepend self. to the method name.

class User
  def self.find_by_geography(options)
    # ... custom geographic finder logic ...
  end
end

And the method is called in exactly the same fashion.

@users = User.find_by_geography(options)

QUESTION: What is the nature of a method that employs both the self. and the class << self constructs?

The terms metaclass, eigenclass, shadow class, virtual class, or ghost class have been used to refer to the anonymous singleton class in between every object and its class in Ruby. This article will use the term “metaclass.”

How does one access the metaclass? The following defines a method metaclass for every object.

class Object
  def metaclass
    class << self
      self
    end
  end
end
>> cat = 'miaow'
=> "miaow" 
>> cat.metaclass
=> #<Class:#<String:0x525670>>
>> cat.metaclass == cat.class
=> false

Another useful method definition for this article follows.

class Object
  def metaclass?(object)
    self.metaclass == object
  end
end
>> x = cat.metaclass
=> #<Class:#<String:0x525670>>
>> y = 'not cat'.metaclass
=> #<Class:#<String:0x586970>>
>> z = cat.metaclass.metaclass
=> #<Class:#<Class:#<String:0x525670>>>
>> cat.metaclass?(x)
=> true
>> cat.metaclass?(y)
=> false
>> cat.metaclass?(z)
=> false

Let us see an example of a class-level method definition and a self. method definition also declared at the class-level.

class A
  class << self
    def b
      self
    end

    def self.c
      self
    end
  end
end

Two questions come to mind: “How do I call those methods?” “What do they return?”

The answers to method b are easy enough.

>> A.b
=> A
>> A.b == A
=> true

The method b is called from class A. It returns class A.

>> A.b.b.b.b.b.b
=> A

How does one invoke the other method?

>> A.c
NoMethodError: undefined method `c' for A:Class
>> A.metaclass.c
=> #<Class:A>
>> A.metaclass?(A.metaclass.c)
=> true

The method c is called from the metaclass of A. It returns the metaclass of A.

>> A.metaclass.c.c.c.c.c.c
=> #<Class:A>

Let us observe inheritance and if method self.c is inherited.

class B < A
end
>> B.b
=> B
>> B.b.b.b.b.b.b
=> B
>> B.c
NoMethodError: undefined method `c' for B:Class
>> B.metaclass.c
NoMethodError: undefined method `c' for #<Class:B>

Nope.

ONE MORE META

What is the nature of a method that employs both the self. and the class << self constructs and returns self within another class << self construct?

Perhaps a code example is better

class A
  class << self
    def self.meta_metaclass
      class << self
        self
      end
    end
  end
end

Hmmm… that’s a little hard to read. The following should be a little better.

class A

  class << self

    def b
      self
    end

    def self.c
      self
    end

    def self.meta_metaclass
      class << self
        self
      end
    end

  end

end

Since is has similar method defintion to self.c it is most probable that self.meta_metaclass is called the same way.

>> A.metaclass.meta_metaclass
=> #<Class:#<Class:A>>

Yes!

Now for the other question: What is returned?

>> mm = A.metaclass.meta_metaclass
=> #<Class:#<Class:A>>
>> A.metaclass?(mm)
=> false
>> A.metaclass.metaclass?(mm)
=> true

The method self.meta_metaclass returns the metaclass of the metaclass of A

CONUNDRUMS

~ irb -r meta.rb
>> String.metaclass.superclass
=> #<Class:Class>
>> Class.metaclass.superclass
=> #<Class:Class>
>> Object.metaclass.superclass
=> Class

What?

~ irb -r meta.rb
>> Class.metaclass.superclass == Class.metaclass
=> true
>> Class.metaclass.superclass
=> #<Class:Class>
>> Class.metaclass.metaclass.superclass
=> #<Class:#<Class:Class>>
>> Class.metaclass.superclass
=> #<Class:#<Class:Class>>
>> Class.metaclass.superclass == Class.metaclass
=> false

What? What?

~ irb -r meta.rb
>> A.metaclass.c.meta_metaclass.c.meta_metaclass
=> #<Class:#<Class:#<Class:A>>>
>> A.metaclass.c.meta_metaclass.c.meta_metaclass
NoMethodError: undefined method `c' for #<Class:#<Class:A>>
        from (irb):2

What? What? What?

If you answer, truly you have a dizzying intellect.

1 Response to “Meta Meta”

Jim Cropcho - July 14th, 2008 at 12:46 AM

Damn, that's hardcore, nick. I wanna come back to this when I've time and see what I can do with it.

Sorry, comments are closed for this article.