Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why are metaclasses created in ruby?

Tags:

ruby

I m trying to understand the Ruby Object Model. I understood that the instance methods are saved in the class rather than in the objects of the class because it removes redundancy. I read that whenever a class is created, a metaclass is created too for the newly created class. the metaclass stores the class methods. ie the singleton methods of the class are located in the metaclass. eg

class MyClass
  def hi
    'hi object'
  end

  def self.bye
    'bye singleton method'
  end
end

for the above MyClass, a metaclass (say #MyClass) is created too. now the method 'hi' is an instance level method and can be called on all the objects of MyClass. method 'bye' is a singleton method of MyClass and it resides in the #MyClass. the reason (i think so) why 'hi' is saved in MyClass rather than all the objects of MyClass is because it avoids redundancy. But we cant have more than one classes named MyClass. So why not store 'bye' in MyClass rather than in #MyClass, since we cant have more than one MyClass. I have absolutely no idea why this is the way it is and i m just trying to understand the reason behind it.

-----UPDATE----

metaclass store the class information like the singleton methods and other stuff. But since a class is a singleton object(its an instance of class Class and is alone of its type) then why not save all the information in the class itself rather than the metaclass.

like image 485
prasad.surase Avatar asked Jul 09 '13 15:07

prasad.surase


People also ask

What is an instance in Ruby?

In the Ruby programming language, an instance variable is a type of variable which starts with an @ symbol. Example: @fruit. An instance variable is used as part of Object-Oriented Programming (OOP) to give objects their own private space to store data.

What is singleton class Ruby?

A singleton class of an object (or a class) is a class created by Ruby only for this specific object . This class is somehow “hidden” to us, but it is there. When calling a method on this object, Ruby will look first into its singleton class, if there is one, to find that method.

What is meta programming in Ruby?

Metaprogramming is a technique in which code operates on code rather than on data. It can be used to write programs that write code dynamically at run time. MetaProgramming gives Ruby the ability to open and modify classes, create methods on the fly and much more.

What is send method in Ruby?

send is a Ruby method allowing to invoke another method by name passing it any arguments specified. class Klass def hello(*args) "Hello " + args.join(' ') end end k = Klass.new k.send :hello, "gentle", "readers" #=> "Hello gentle readers" Source.


2 Answers

Just to be super duper clear.

Here is a quick ruby script that explains the question:

#!/usr/bin/env ruby
puts ObjectSpace.count_objects[:T_CLASS] #>> 471
class X
  def self.foo
  end
  def bar
  end
end
puts ObjectSpace.count_objects[:T_CLASS] #>> 473

This is what the OP meant by "ObjectSpace.count_objects[:T_CLASS] increments the count by 2." Let's call the extra class the singleton class of X, because that appears to be what Ruby calls it internally.

irb> X
=> X
irb> X.singleton_class
=> <Class: X>

Notice that the #foo method is an instance method of X.singleton_class, not X.

irb> X.instance_methods(false)
=> [:baz]
irb> X.singleton_class.instance_methods(false)
=> [:foo]

So why is :foo stored in X.singleton_class instead of X? Isn't there only ever going to be one X?

I believe the main reason is for consistency. Consider the following, simpler scenario concerning plain instance objects.

car = Car.new
def car.go_forth_and_conquer
end

As @mikej explained superbly, this new method is stored in car's singleton class.

irb> car.singleton_class.instance_methods(false)
=> [:go_forth_and_conquer]

Classes are Objects

Now, classes are objects too. Each class is an instance of Class. Thus, when a class (say, X) is defined, ruby is really creating an instance of Class, and then adding methods to the instance (similar to what we did to car above.) For example, here is an alternative way to create a new class

Car = Class.new do
  def go_forth_and_conquer
    puts "vroom"
  end
end
Car.new.go_forth_and_conquer

Therefore, it is much easier to just reuse the code and do it the same way (i.e. keep foo in X.singleton_class.) This probably requires less effort and will lead to fewer surprises, so no one will ever need to write code to handle Class instances differently from other instances.

Probably Doesn't Matter

You might be thinking that if Ruby did not have singleton classes for instances of Class, there could be some memory savings. However, it sounds to me that where bar is actually stored is an implementation detail that we probably shouldn't count on. Rubinius, MRI, and JRuby could all store methods and instances differently, as long as the behavior is consistent. For all we know, there could be a reasonable implementation of Ruby that doesn't eagerly create singleton classes for class objects, for the exact same reasons you outlined, as long as the overall behavior conforms to the ruby spec. (E.g. an actual singleton class doesn't exist until the #singleton_class method is first invoked.)

like image 118
James Lim Avatar answered Oct 05 '22 05:10

James Lim


This isn't quite an answer to your question, but it might be useful. Two things to think about that might help:

  • metaclass is not really a good name for what's going on here when you think of how the meta prefix is used in other scenarios. eigenclass which you will see used in other documentation is probably a better name, meaning "an object's own class"
  • It's not just classes that have an eigenclass, every object does

The eigenclass is used to store methods that are specific to a particular object. e.g. we can add a method to a single String object:

my_string = 'Example'
def my_string.example_method
  puts "Just an example"
end

This method can only be called on my_string and not on any other String object. We can see that it is stored in my_string's eigenclass:

eigenclass = class << my_string; self; end # get hold of my_string's eigenclass
eigenclass.instance_methods(false) # => [:example_method]

Remembering that classes are objects, in this context, it makes sense that the methods specific to a particular class should be stored in that class's eigenclass.


Update: actually, there is an eigenclass for the eigenclass. We can see this more easily if we add eigenclass as a method to Object:

class Object 
  def eigenclass 
    class << self
      self
    end 
  end 
end

and then we can do:

irb(main):049:0> my_string.eigenclass
=> #<Class:#<String:0x269ec98>>
irb(main):050:0> my_string.eigenclass.eigenclass
=> #<Class:#<Class:#<String:0x269ec98>>>
irb(main):051:0> my_string.eigenclass.eigenclass.eigenclass # etc!
=> #<Class:#<Class:#<Class:#<String:0x269ec98>>>>

whilst this seemingly creates an infinite regress, this is avoided because Ruby only creates the eigenclasses on as they are needed. I think the name "metaclass" really is a source of part your confusion because you are expecting a "metaclass" to hold some kind of information that it actually doesn't.

like image 41
mikej Avatar answered Oct 05 '22 03:10

mikej