Take me home

Classes and constants magic

Written by August Lilleaas, published September 01, 2008

An anonymous class!

bear = Class.new

puts bear
# => #<Class:0x8ef08>

puts bear.class
# => Class

puts bear.name
# => ""

This class has no name, it's anonymous. Let's create an instance of the anonymous class.

b = bear.new
puts b.class
#=> #<Class:0x8ef08>

Normally, b.class would return the class name. Anonymous means no name. Ruby returns an instance of class (the one created with Class.new) insntead.

A class name is always a constant. The call class Foo; end tells Ruby to create an instance of Class and assign that instance to the constant Foo. These two calls are equal:

class Foo; end
Foo = Class.new

Let's try this with our anonymous class. We're assigning the instance of Class stored in the variable bear to a constant, Bear.

Bear = bear

puts b.class
# => Bear

puts b.name
# => "Bear"

It now reports Bear as the class name, because it's no longer anonymous.

Our instance of Class seems to have vanished, but it's still possible to access this instance directly.

class << Bear
  puts self
  # => #<Class:Bear>
end

It couldn't hide from us after all. The special (class <<) syntax lets us access it. It also says Bear rather than 0x8ef08, to let us know that this class is no longer anonymous.

This secret and hidden instance of Class is what rubyists refers to as the _metaclass_ of a class. #<Class:Bear> is the metaclass of Bear.

It's this metaclass that holds all the class methods. That makes sense, because a constant can't have methods. Instances is the only thing in Ruby that has methods.

Important summary: Class methods of a class are simply instance methods of its metaclass. Read this out loud 10 times.

Code speaks louder than words

Bear.class_eval do
  def say_hello
    puts "Hello!"
  end
end

Bear.say_hello
# => NoMethodError: undefined method ‘say_hello’ for Bear:Class

We need to define the method on the metaclass, the instance of Class.

class << Bear
  def say_hello
    puts "Hello!"
  end
end

Bear.say_hello
# => "Hello!"

Further reading

_why the lucky stiff has more on the subject.


Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.