[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

What's the difference between send and instance_eval?

michele

10/23/2006 10:12:00 PM

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.

11 Answers

Tim Pease

10/23/2006 10:54:00 PM

0

On 10/23/06, michele <michelemendel@gmail.com> wrote:
> 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.
>

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

michele

10/24/2006 4:06:00 PM

0


So there is no need for "send"?

Thanks


On Oct 24, 12:54 am, "Tim Pease" <tim.pe...@gmail.com> wrote:
> On 10/23/06, michele <michelemen...@gmail.com> wrote:
>
> > 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.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

Joel VanderWerf

10/24/2006 4:53:00 PM

0

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).

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Tim Pease

10/24/2006 7:27:00 PM

0

On 10/24/06, michele <michelemendel@gmail.com> 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.oreillynet.com/ruby/blog/2005/12/what_is_...
http://www.artima.com/rubycs/articles/ruby_a...

Tomasz Wegrzanowski

10/24/2006 11:09:00 PM

0

On 10/24/06, michele <michelemendel@gmail.com> 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 ;-)

--
Tomasz Wegrzanowski [ http://t-a-w.blo... ]

Wilson Bilkovich

10/25/2006 2:04:00 AM

0

On 10/24/06, Tomasz Wegrzanowski <tomasz.wegrzanowski@gmail.com> wrote:
> On 10/24/06, michele <michelemendel@gmail.com> 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 ;-)

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

Heh.

michele

10/26/2006 6:01:00 AM

0

This works:

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


On Oct 24, 6:53 pm, Joel VanderWerf <v...@path.berkeley.edu> wrote:
> 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 theinstance_evalblock.
>
> 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).
>
> --
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf

10/26/2006 6:54:00 AM

0


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.)

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Rick DeNatale

10/26/2006 3:25:00 PM

0

On 10/26/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

> 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.)

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.denh...

Joel VanderWerf

10/26/2006 5:47:00 PM

0

Rick DeNatale wrote:
> On 10/26/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
>
>> 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.)
>
> 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.

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.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407