views:

544

answers:

4
Foo = Class.new
Foo.class_eval do
  def class_bar
    "class_bar"
  end
end
Foo.instance_eval do
  def instance_bar
    "instance_bar"
  end
end
Foo.class_bar       #=> undefined method ‘class_bar’ for Foo:Class
Foo.new.class_bar   #=> "class_bar"
Foo.instance_bar       #=> "instance_bar"
Foo.new.instance_bar   #=> undefined method ‘instance_bar’ for #<Foo:0x7dce8>

Just based on the name of the methods, I would expect class_eval to allow you to add a class method to Foo and instance_eval to allow you to add an instance method to Foo. But they seem to do the opposite.

In the example above if you call class_bar on the Foo class you get an undefined method error and if you call instance_bar on the instance returned by Foo.new you also get an undefined method error. Both errors seem to contradict an intuitive understanding of what class_eval and instance_eval should do.

What is really the difference between these methods?

Documentation for class_eval:

mod.class_eval(string [, filename [, lineno]]) => obj

Evaluates the string or block in the context of mod. This can be used to add methods to a class.

Documentation for instance_eval:

obj.instance_eval {| | block } => obj

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables.

+1  A: 

I think you got it wrong. class_eval adds the method in the class, so all instances will have the method. instance_eval will add the method just to one specific object.

foo = Foo.new
foo.instance_eval do
  def instance_bar
    "instance_bar"
  end
end

foo.instance_bar      #=> "instance_bar"
baz = Foo.new
baz.instance_bar      #=> undefined method
Renato Besen
You're calling instance_eval on the object foo while I'm calling it on the class Foo. I don't see how this relates.
pez_dispenser
+2  A: 

instance_eval effectively creates a singleton method for the object instance in question. class_eval will create a normal method in the given class's context, available to all objects of that class.

Here's a link regarding singleton methods and the singleton pattern(non-ruby specific)

jess
Thanks for the links!
pez_dispenser
+10  A: 

As the documentation says, class_eval evaluates the string or block in the context of the Module or Class. So the following pieces of code are equivalent:

class String
  def lowercase
    self.downcase
  end
end

String.class_eval do
  def lowercase
    self.downcase
  end
end

In each case, the String class has been reopened and a new method defined. That method is available across all instances of the class, so:

"This Is Confusing".lowercase 
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
=> "the smiths on charlie's bus"

class_eval has a number of advantages over simply reopening the class. Firstly, you can easily call it on a variable, and it's clear what your intent is. Another advantage is that it will fail if the class doesn't exist. So the example below will fail as Array is spelt incorrectly. If the class was simply reopened, it would succeed (and a new incorrect Aray class would be defined):

Aray.class_eval do
  include MyAmazingArrayExtensions
end

Finally class_eval can take a string, which can be useful if you're doing something a little more nefarious...

instance_eval on the other hand evaluates code against a single object instance:

confusing = "This Is Confusing"
confusing.instance_eval do
  def lowercase
    self.downcase
  end
end   

confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String

So with instance_eval, the method is only defined for that single instance of a string.

So why does instance_eval on a Class define class methods?

Just as "This Is Confusing" and "The Smiths on Charlie's Bus" are both String instances, Array, String, Hash and all other classes are themselves instances of Class. You can check this by calling #class on them:

"This Is Confusing".class
=> String

String.class
=> Class

So when we call instance_eval it does the same on a class as it would on any other object. If we use instance_eval to define a method on a class, it will define a method for just that instance of class, not all classes. We might call that method a class method, but it is just an instance method for that particular class.

tomafro
This is a terrific explanation. Thanks. I followed you all the way up until the last paragraph where you try to explain why instance_eval defines class methods when called on a Class. The last line is particularly difficult for me to digest: "Calling it a class method is a mistake, it's just an instance method on that particular Class instance." Do you mean that all class methods are nothing more than that?
pez_dispenser
Yeah, exactly - that's all they are. I will try and make it clearer tomorrow.
tomafro
Fantastic - I just added a new question specifically for that issue: "Why does instance_eval() define a class method when called on a class?" http://stackoverflow.com/questions/900704/why-does-instanceeval-define-a-class-method-when-called-on-a-class.
pez_dispenser
Great - I'll try and answer that one too then ;)
tomafro
+2  A: 

The other answer is correct, but allow me to go in depth a little.

Ruby has a number of different kinds of scope; six according to wikipedia, though detailed formal documentation seems to be lacking. The kinds of scope involved in this question are, not surprisingly, instance and class.

The current instance scope is defined by the value of self. All unqualified method calls are dispatched to the current instance, as are any references to instance variables (which look like @this).

However, def is not a method call. The target for methods created by def is the current class (or module), which can be found with Module.nesting[0].

Let's see how the two different eval flavors affect these scopes:

String.class_eval { [self, Module.nesting[0]] } => [String, String] String.instance_eval { [self, Module.nesting[0]] } => [String, #<Class:String>]

In both cases, the instance scope is the object on which *_eval is called.

For class_eval, the class scope also becomes the target object, so def creates instance methods for that class/module.

For instance_eval, the class scope becomes the singleton class (aka metaclass, eigenclass) of the target object. Instance methods created on the singleton class for an object become singleton methods for that object. Singleton methods for a class or module are what are commonly (and somewhat inaccurately) called class methods.

The class scope is also used to resolve constants. Class variables (@@these @@things) are resolved with class scope, but they skip over singleton classes when searching the module nesting chain. The only way I have found to access class variables in singleton classes is with class_variable_get/set.

jedediah
+1 for also introducing scope here, in addition to only self by other answers.
bryantsai
btw, this only works under 1.9.
bryantsai