What's the difference between send and instance_eval?

Discussion in 'Ruby' started by michele, Oct 23, 2006.

  1. michele

    michele Guest

    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.
    michele, Oct 23, 2006
    #1
    1. Advertising

  2. michele

    Tim Pease Guest

    On 10/23/06, michele <> 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 :mad:length #=> 4


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

    Blessings,
    TwP
    Tim Pease, Oct 23, 2006
    #2
    1. Advertising

  3. michele

    michele Guest

    So there is no need for "send"?

    Thanks


    On Oct 24, 12:54 am, "Tim Pease" <> wrote:
    > On 10/23/06, michele <> 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 :mad:length #=> 4
    >
    > It's a dumb example, but it should convery the differences.
    >
    > Blessings,
    > TwP
    michele, Oct 24, 2006
    #3
  4. 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
    Joel VanderWerf, Oct 24, 2006
    #4
  5. michele

    Tim Pease Guest

    On 10/24/06, michele <> 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_a_dsl.html
    http://www.artima.com/rubycs/articles/ruby_as_dsl.html
    Tim Pease, Oct 24, 2006
    #5
  6. On 10/24/06, michele <> 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.blogspot.com/ ]
    Tomasz Wegrzanowski, Oct 25, 2006
    #6
  7. On 10/24/06, Tomasz Wegrzanowski <> wrote:
    > On 10/24/06, michele <> 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.
    Wilson Bilkovich, Oct 25, 2006
    #7
  8. michele

    michele Guest

    This works:

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


    On Oct 24, 6:53 pm, Joel VanderWerf <> 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
    michele, Oct 26, 2006
    #8
  9. 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
    Joel VanderWerf, Oct 26, 2006
    #9
  10. On 10/26/06, Joel VanderWerf <> 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.denhaven2.com/
    Rick DeNatale, Oct 26, 2006
    #10
  11. Rick DeNatale wrote:
    > On 10/26/06, Joel VanderWerf <> 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
    Joel VanderWerf, Oct 26, 2006
    #11
  12. michele

    michele Guest

    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.


    On Oct 26, 7:47 pm, Joel VanderWerf <> wrote:
    > Rick DeNatale wrote:
    > > On 10/26/06, Joel VanderWerf <> 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
    michele, Oct 26, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jakk
    Replies:
    4
    Views:
    12,053
  2. Santa
    Replies:
    1
    Views:
    1,062
    Mark A. Odell
    Jul 17, 2003
  3. Thomas Rachel
    Replies:
    0
    Views:
    189
    Thomas Rachel
    Jan 7, 2013
  4. Steven D'Aprano
    Replies:
    1
    Views:
    113
    Chris Angelico
    Jan 7, 2013
  5. Philipp Hagemeister
    Replies:
    0
    Views:
    150
    Philipp Hagemeister
    Jan 8, 2013
Loading...

Share This Page