What's the difference between send and instance_eval?

What’s the difference between send and instance_eval (except the
obvious syntax)?

I’ve been trying to figure out why Ruby has them both. It seems you can
use them intechangeably, at least in the cases I’ve found and tested
(so the question is if there is a case where can’t change one for the
other).

Sorry if this has been answered already. I really tried to find the
answers in my Ruby and Rails books and on the Internet before posting
the question here.

On 10/23/06, michele [email protected] wrote:

the question here.

send can only be used to execute existing methods on objects.

instance_eval allows you to do much more – i.e. adding instance
variables, tinkering with private methods, etc

ary = %w( 1 2 3 4 )

ary.send :length #=> 4

ary.instance_eval do
@length = self.length
end

ary.instance_variable_get :@length #=> 4

It’s a dumb example, but it should convery the differences.

Blessings,
TwP

So there is no need for “send”?

Thanks

michele wrote:

So there is no need for “send”?

One use of #send:

a=[]
@x=3
a.send :<<, @x
p a

@x=4
a.instance_eval { self << @x }
p a

END

Output:

[3]
[3, nil]

This is because @x is in a different scope inside the instance_eval
block.

Another case, showing the real point of #send:

msg = :reverse
a = [1,2,3]
b = a.send msg
p b

END

Output:

[3, 2, 1]

There’s no easy equivalent with #instance_eval and blocks (you could
mess with strings, though).

On 10/24/06, michele [email protected] wrote:

So there is no need for “send”?

Thanks

Actually, I use send quite often – more so than instance_eval. When I
write unit tests, I use send all the time to call the private methods
of the objects I’m testing.

I use instance_eval when I’m doing things with domain specific languages
(DSLs).

Both are equally useful – it’s just a matter of learning when to use
which one.

Oh, and no need to apologize for asking questions. The people here are
quite friendly.

Blessings,
TwP

By the way, here are two good articles about DSLs … one is theory,
the other is practice.

http://www.artima.com/rubycs/articles/ruby_as_dsl.html

On 10/24/06, Tomasz W. [email protected] wrote:

Now try that with instance_eval :wink:

def method_missing(m, args, &block)
@obj.instance_eval { self.send(m, args, &block) }
end

Heh.

This works:

msg = :reverse
a = [1,2,3]
a.instance_eval(msg.to_s)

On 10/24/06, michele [email protected] wrote:

So there is no need for “send”?

But there obviously is - method in send doesn’t have to be a constant.

# A delegator
def method_missing(m, args, &blk)
    @obj.send(m, args, &blk)
end

Now try that with instance_eval :wink:

On 10/26/06, Joel VanderWerf [email protected] wrote:

array. (It’s possible, but painful, and you lose the identity of the
hash h.)

except that instance_eval can take a block in lieu of a string:

a.instance_eval {concat [1,2,3,4,5,6,IO,String,Kernel, h]}
=> [1, 2, 3, 1, 2, 3, 4, 5, 6, IO, String, Kernel, {1=>2}]

Not that I think that send should be eliminated, both methods are
useful. Horses for courses.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Rick DeNatale wrote:

To make the instance_eval work here, you would have to find a way to
useful. Horses for courses.
And I’m starting to beat a dead horse here, but using a block leads you
to scoping issues. (What if the hash were @h or a method call instead of
h? You can always use an temporary local var to avoid the issue.)

You’re quite right: each method has its place.

Putting the comments in order…

Joel VanderWerf wrote:

Another case, showing the real point of #send:

msg = :reverse
a = [1,2,3]
b = a.send msg
p b

END

Output:

[3, 2, 1]

There’s no easy equivalent with #instance_evaland blocks (you could
mess with strings, though).

michele wrote:

This works:

msg = :reverse
a = [1,2,3]
a.instance_eval(msg.to_s)

That’s true, but only because I chose a bad example. Here’s a better
one:

h = {1=>2}
msg = [:concat, [4, 5, 6, IO, String, Kernel, h]]
a = [1,2,3]
p a.send(*msg) # ==> [1, 2, 3, 4, 5, 6, IO, String, Kernel, {1=>2}]
p a.instance_eval(msg.to_s) # ==> NameError

To make the instance_eval work here, you would have to find a way to
turn the argument array into a string that, when eval-ed, is that same
array. (It’s possible, but painful, and you lose the identity of the
hash h.)

I may not understand it well, but I don’t like it. The two methods are
so similar that the only way to figure out the difference is to find
cases that will make it hard or impossible to use one of them. It
should be easy to choose which method to use, not hard to figure out
which one not to use. They are also conceptually different. An object
can either call a method (most common lingo among Java, C, etc) or you
can send it a message (Smalltalk), but what does “eval” mean? Ruby uses
all three (call, send and eval) which may be good (I don’t know why,
but maybe if you like to study computer languages), but if I don’t use
these methods every day, I will have to think hard every time I need
one of them.