Fun with Ruby’s instance_eval and class_eval

In an attempt to better understand instance_eval and class_eval, I just read Khaled’s post on Ruby reflection. It helped, and I came up with a memory crutch I can use to remember when to use each of them:

Use ClassName.instance_eval to define class methods.

Use ClassName.class_eval to define instance methods.

That’s right. Not a typo. Here are some examples, shamelessly stolen from his post:

# Defining a class method with instance_eval
Fixnum.instance_eval { def ten; 10; end }
Fixnum.ten #=> 10

# Defining an instance method with class_eval
Fixnum.class_eval { def number; self; end }
7.number #=> 7

I Like Stuff that’s Backwards

Why is it the reverse of what you might expect? Because Fixnum.instance_eval treats Fixnum as an instance (an instance of the Class class), thus any new functions you define can be called on that instance. So it’s equivalent to this:

class Fixnum
  def self.ten
    10
  end
end
Fixnum.ten #=> 10

Fixnum.class_eval treats Fixnum as a class and executes the code in the context of that class, thus any “def” statements are treated exactly as if they were in normal code without any reflection. It’s equivalent to this:

class Fixnum
  def number
    self
  end
end
7.number #=> 7

There are still some things about Ruby reflection that mystify me but at least I think I’ve got this one nailed.

About these ads

15 Responses to “Fun with Ruby’s instance_eval and class_eval”

  1. khellls Says:

    A very nice explanation :)

  2. Justin George Says:

    But what about module_eval? Oh god, won’t someone think of the modules!

  3. Ed Ruder Says:

    The Pragmatic Programmers have a “Ruby Metaprogramming” screencast series ($$) that delves deeply into these and many more Ruby “mysteries”–I recommend them!

  4. Fredrik W Says:

    That’s the same way I think of it. It’s a real gotcha when you start doing these kinds of things though :)

  5. Shamika Says:

    Thanx thanx wonderful explanation….. Short and clean

  6. rakesh Says:

    Very beautifully explained. thanks. i was pretty confused before reading ur post

  7. David Says:

    Well now then how do these things compare to define_method? :)

  8. Jeremy Says:

    Thanks, this was the perfect treatment that quickly gave me what I needed!

  9. The "Tech. Arch." Says:

    [...] Fun with Ruby’s instance_eval and class_eval (by Brian Morearty) [...]

  10. Monitoring the AWS-S3 gem in RPM : Custom Instrumentation Part 2 « Says:

    [...] the original class file, as instance methods. If these eval methods still seem strange, check out Brian Morearty’s nice and simple blog post that demonstrates the differences between them. While we could just re-open the Bucket class and [...]

  11. Andy Says:

    Brian, I have to disagree. instance_eval works on the particular instance. Fixnum here is an object, an instance, in particular an object of type Class. When you add methods to an instance, it only affects the instance. Hence, you get class methods when you apply instance_eval to an instance of Class. using class_eval is simply like opening up the Fixnum class and adding methods, so any all instances of Fixnum get instance methods themselves. If you take an instance of Fixnum and apply instance_eval only that instance would get the method, so you could Fixnum.new.instance_eval so you could dynamically extend a single instance of type Fixnum without affecting other instances.

    • Brian Morearty Says:

      Thanks for the comments, Andy. You said you disagree but I think we actually agree with how instance_eval and class_eval work. I was trying to say exactly what you said. Sorry if it wasn’t clear.

  12. Andy Says:

    I guess more to the point, I find the mnemonic misleading. I don’t find it backwards, if you take the perspective that everything in Ruby is an object.

    • Brian Morearty Says:

      I agree that it’s not backward if you take the perspective that everything is an object. That’s why I tried to explain it by saying Fixnum.instance_eval treats Fixnum as an instance of the Class class. It seems like it helped a bunch of the other commenters to remember not only which method is which but to actually understand why.

      But for those to whom the rationale still doesn’t make sense, I think there’s nothing wrong with a good memory crutch once in a while.

  13. Brian Morearty Says:

    In case my explanation above didn’t quite work for you, here’s another one that says the exact same thing but with different examples. Check it out:

    http://lesseverything.com/blog/archives/2012/08/01/the-difference-between-instance_eval-and-class_eval-in-ruby/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: