Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is 'yield self' the same as instance_eval?

Tags:

Is there any difference if you define Foo with instance_eval: . . .

class Foo     def initialize(&block)       instance_eval(&block) if block_given?     end   end 

. . . or with 'yield self':

class Foo   def initialize     yield self if block_given?   end end 

In either case you can do this:

x = Foo.new { def foo; 'foo'; end } x.foo  

So 'yield self' means that the block after Foo.new is always evaluated in the context of the Foo class.

Is this correct?

like image 647
uzo Avatar asked Sep 15 '09 03:09

uzo


1 Answers

Your two pieces of code do very different things. By using instance_eval you're evaluating the block in the context of your object. This means that using def will define methods on that object. It also means that calling a method without a receiver inside the block will call it on your object.

When yielding self you're passing self as an argument to the block, but since your block doesn't take any arguments, it is simply ignored. So in this case yielding self does the same thing as yielding nothing. The def here behaves exactly like a def outside the block would, yielding self does not actually change what you define the method on. What you could do is:

class Foo   def initialize     yield self if block_given?   end end x = Foo.new {|obj| def obj.foo() 'foo' end} x.foo 

The difference to instance_eval being that you have to specify the receiver explicitly.

Edit to clarify:

In the version with yield, obj in the block will be the object that is yielded, which in this case is is the newly created Foo instance. While self will have the same value it had outside the block. With the instance_eval version self inside the block will be the newly created Foo instance.

like image 165
sepp2k Avatar answered Sep 18 '22 08:09

sepp2k