eval, bindings and scope

Discussion in 'Ruby' started by hellfeuer@gmail.com, Jun 22, 2007.

  1. Guest

    hey

    i have a question:
    if i do this in the top level:
    > foo = lambda {p a}
    > eval "a=1"
    > foo.call


    It doesn't work, giving me a NameError: undefined variable or method in
    main:Object

    but whats perhaps wierder, is if i do this:
    > foo = lambda {p b}
    > eval "b=1", foo
    > foo.call


    it gives the same error, but
    > p b

    now works. that is, b is bound in the global scope

    now my understanding is:
    1) the first version should bind 'a' in the global scope (it does), and
    foo should now be able to access it (it cant)
    2) the second version should bind 'b' in the context of foo's binding
    therefore making it local to foo, so foo should still be able to access
    b, but it should not be visible in the top level.. yet the opposite
    behaviour is observed

    how come?? what am i missing here?

    thnx

    --
    Posted via http://www.ruby-forum.com/.
     
    , Jun 22, 2007
    #1
    1. Advertising

  2. On Jun 22, 2007, at 11:33 AM, wrote:

    > if i do this in the top level:
    >> foo = lambda {p a}
    >> eval "a=1"
    >> foo.call

    >
    > It doesn't work, giving me a NameError: undefined variable or
    > method in
    > main:Object


    It will work if the local variable has been defined before the Proc
    object is created. That is, the local variable must exist before the
    closure is made.

    <code>
    a = nil
    foo = lambda { a }
    eval("a = 42")
    foo.call # => 42
    </code>

    Regards, Morton
     
    Morton Goldberg, Jun 22, 2007
    #2
    1. Advertising

  3. Hell Feuer Guest

    hmmm.. thnx. ur right. but even accepting that thats just how closures
    are, what about my second version?

    > foo = lambda {p b}
    > eval "b=1", foo
    > foo.call


    1) why does b get bound in the global scope??? shouldn't it become local
    to to foo?

    2) and in any case, since b=1 is being evaluated in the context of foo's
    binding, and foo is being called later, shouldn't this be equivalent to
    defining b before foo is called (and therefore this shouldn't give an
    error)??

    3) if not, what does passing foo to eval actually do, since the
    behaviour seems to be the same whether or not i pass foo (i.e. the
    variable is bound in the global scope, and the closure cannot see it)


    --
    Posted via http://www.ruby-forum.com/.
     
    Hell Feuer, Jun 22, 2007
    #3
  4. On Jun 22, 2007, at 5:57 PM, Hell Feuer wrote:

    > hmmm.. thnx. ur right. but even accepting that thats just how closures
    > are, what about my second version?
    >
    >>> foo = lambda {p b}
    >>> eval "b=1", foo
    >>> foo.call

    >
    > 1) why does b get bound in the global scope???


    There is nothing in your lambda to establish a binding for b.

    > shouldn't it become local to to foo?


    No.

    > 2) and in any case, since b=1 is being evaluated in the context of
    > foo's
    > binding, and foo is being called later, shouldn't this be
    > equivalent to
    > defining b before foo is called (and therefore this shouldn't give an
    > error)??


    Only assignment brings b into existence.

    > 3) if not, what does passing foo to eval actually do, since the
    > behaviour seems to be the same whether or not i pass foo (i.e. the
    > variable is bound in the global scope, and the closure cannot see it)


    The binding of the Proc object is passed to eval.

    Your second example suffers from the same problem as your first.

    Also, consider the following tow examples:

    <code>
    bar = lambda { |b| b = b }
    b = 0
    bar.call(42) # => 42
    b # => 0
    </code>

    <code>
    b = 0
    bar = lambda { |b| b = b }
    bar.call(42) # => 42
    b # => 42
    </code>

    In the first case, b is local to the block because no previous
    definition is visible, but in the second b is not local to the block
    because a previous definition is visible.

    Finally, here is a quote from the pickaxe book that might clarify
    things for you:

    <quote>
    As of Ruby 1.8,local variables assigned within an eval are available
    after the eval
    only if they were defined at the outer scope before the eval
    executed. In this way eval
    has the same scoping rules as blocks.
    </quote>

    Regards, Morton
     
    Morton Goldberg, Jun 23, 2007
    #4
  5. Sami Samhuri Guest

    On 6/22/07, <> wrote:
    > hey

    Hi!

    > i have a question:

    A nice one too. I learned quite a bit from it so thank you.

    After reading up on procs, evals, and lambdas in the pickaxe book I
    think I understand your question. This irb snippet is where I realised
    exactly what was going on so maybe it will help you as well.

    sjs@tuono% ruby -v
    ruby 1.8.6 (2007-03-13 patchlevel 0) [x86_64-linux]
    sjs@tuono% irb
    irb(main):001:0> p = lambda {a=:a; binding}
    => #<Proc:0x00002b17e252f1a0@(irb):1>
    irb(main):002:0> binding = p.call
    => #<Binding:0x2b17e252a2b8>
    irb(main):003:0> eval "p a", binding
    :a
    => nil
    irb(main):004:0> p a
    NameError: undefined local variable or method `a' for main:Object
    from (irb):4
    irb(main):005:0> eval "b=:b", binding
    => :b
    irb(main):006:0> b
    NameError: undefined local variable or method `b' for main:Object
    from (irb):6

    > 2) the second version should bind 'b' in the context of foo's binding
    > therefore making it local to foo, so foo should still be able to access
    > b, but it should not be visible in the top level.. yet the opposite
    > behaviour is observed
    >
    > how come?? what am i missing here?


    This is how you you would define b in a given context, local to that
    context. I don't think you were misunderstanding the expected
    behaviour, just the method of describing that behaviour.

    sjs@tuono% irb
    irb(main):001:0> p = lambda {a=:inside; binding}
    => #<Proc:0x00002b321f1aee48@(irb):1>
    irb(main):002:0> binding = p.call
    => #<Binding:0x2b321f1a9c40>
    irb(main):003:0> p a # this is the same as: eval "p a"
    NameError: undefined local variable or method `a' for main:Object
    from (irb):3
    irb(main):004:0> eval "p a", binding
    :inside
    => nil
    irb(main):005:0> a = :eek:utside
    => :eek:utside
    irb(main):006:0> b = a
    => :eek:utside
    irb(main):007:0> eval "c = a", binding
    => :inside
    irb(main):008:0> c
    NameError: undefined local variable or method `c' for main:Object
    from (irb):9
    irb(main):009:0> eval "b = a", binding
    => :inside
    irb(main):010:0> b
    => :inside

    Hope this helps!

    --
    Sami Samhuri
     
    Sami Samhuri, Jun 23, 2007
    #5
    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. DataBinder.Eval and Eval.

    , Jun 16, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    548
    Karl Seguin [MVP]
    Jun 16, 2006
  2. Steve V
    Replies:
    6
    Views:
    237
    Steve V
    Apr 20, 2005
  3. Liang Wang
    Replies:
    8
    Views:
    134
    Ben Morrow
    Feb 2, 2008
  4. bernd
    Replies:
    2
    Views:
    653
    bernd
    Jan 26, 2012
  5. Adam C.

    Controlling the bindings within an eval

    Adam C., Jul 10, 2008, in forum: Javascript
    Replies:
    4
    Views:
    66
    Lasse Reichstein Nielsen
    Jul 10, 2008
Loading...

Share This Page