Thursday, July 24, 2008

Metaclasses and Ruby Inheritance Chain

This is a very large and involved topic. (great topic! it is part of what makes Ruby so powerful)
You can add new methods to a Class on the fly at anytime. Can also overwrite methods at any time. And, in Ruby, this truly means virtually any Class. Including classes like Array, String, etc.

Let's say we have

> class Course
> attr_accessor :id, :name
> def initialize( id, name)
> @id, @name= id, name

> end
> end

> c = Course.new( 1, "Augusta National" )
=> #<
Course:0x81cfb94 @id=1, @name="Augusta National"...

> c.class
=> Course

> c.id
=> 1
> c.name
=> "Augusta National"


So in this case, a Course object, once initialized, will have a
@id and a @course variable. It can hold
any other variables at any time too...

> c.instance_variable_set( "@par", 72 )
=> 72
> c.par
=> MoMethodError: undefined method 'par' for #<Course..

It's holding that variable for par, but now we cannot get at it without a read method. So let's say you
wanted to only have the reader/writer methods for par on that instance,
not on the class
(just an example).


Classes hold methods, objects do not. Except in the case of metaclasses:
> class << c
> attr_accessor :par
> def pretty_par
> puts "par: #{@par}"
> end
> end

Now you can do
> c.par
=> 72
Also when you do:
> c.methods
=> ["par", "id", "name", "pretty_par", ...] #=> these are referred to as the
#=> object's "Singleton methods"

but when you show the methods for the Course class:
> Course.methods
=> ["id", "name", ...] # i.e. no par, or pretty_par, because there is no method
# for these in the Course class, only the c metaclass
likewise:

> c2 = Course.new(2, "Shinnecock Hills")
=>
#<Course:0x91cfb94 @id=2, @name="Shinnecock Hills"

but it won't have access to any of the Singleton methods in c (i.e. neither "c2.par", nor "c2.pretty_par" method
calls will work. They only work in the c metaclass).


You see, because when Ruby looks for a method, it first looks at the metaclass.
i.e. the metaclass intercepts the request, and checks for methods there first.

Then it goes to the object's class, then the SuperClass of that object, then any super's of that object and so on
...all the way back to the Object base class.


You can insert methods into the class, or into an object's metaclass at any level in the inheritance chain.
Very powerful.



One more beauty... if you attach a:
...
def method_missing
puts "there was no method that matched that"
end
...
you can intercept the call to a missing method (anywhere in the inheritance chain, the class, the metaclass, etc)
and do things like creating methods on the fly, programmatically.

It's called "monkey patching" (some people call it "Duck punching", and there are other names).
Ruby is a great language to metaprogram with. Rails uses method_missing often (along with const_missing) --
for instance, ActiveRecord uses method_missing to dynamically support the find_ methods.

That's a whole other interesting topic in itself to explore!

5 comments:

petertparker said...

Hi Nice Blog Welcome to prodigyapex's web development services services.Our missionis to deliver high quality web design and development at reasonable prices. Explore our site and compare our prices - we're confident we an provide a web presence solution for you.wide variety of solutions based on your needs. To begin, we provide detailed proposals for your project. We are able to work small projects on an hourly basis or develop package deals for the more involved projects. We also provide turn-key solutions for your web presence needs.

achyut said...

Its highly informative. I would be visiting your blog hereafter regularly to gather valuable information.

Freelance Web Developer India

kristinawils said...

Great post and very well written, that will really help you Professionally qualified. hire php programmers accessible through 'Web Art Sense' is directed towards giving you the best outcome of our expertise. You can find out many useful information about web design, seo and his work by visiting his blog and I Just wanna say thanks you for the information you have shared.

dedicated php programmer

Jesus said...

Hey, nice site you have here! Keep up the excellent work!

Mobile Applications Development

kaviya said...

My cousin recommended this blog and she was totally right keep up the fantastic work!



Ruby Development