Eval needs explicit self for accessor methods?

Discussion in 'Ruby' started by tfdj, Apr 1, 2006.

  1. tfdj

    tfdj Guest

    hi all!

    i encountered a strange problem with eval. please see the following
    test case:


    require 'test/unit'

    class TestContext

    def eval_in_context( ruby_code )
    instance_eval ruby_code
    end

    def toast
    @toast
    end

    def toast=( val )
    @toast = val
    end

    end



    class TestMetaEval < Test::Unit::TestCase

    def test_toast
    tc = TestContext.new
    tc.toast = 'yes'

    assert_equal 'yes', tc.toast
    assert_equal 'yes', tc.eval_in_context( "toast" )

    # These two lines - using explicit self - work as expected:
    assert_equal 'maybe', tc.eval_in_context( "self.toast = 'maybe'" )
    assert_equal 'maybe', tc.toast

    # What is happening here:
    assert_equal 'no', tc.eval_in_context( "toast = 'no'" )

    # Why does the next test fail?
    # What did the previous line set? A local variable?

    # tc.toast returns 'maybe' here instead of the expected 'no':
    assert_equal 'no', tc.toast
    end

    end


    why is the 'toast=(val)' method not visible in eval unless i
    explicitly use "self.toast = ..."?

    what is it i don't understand about ruby scoping? :/

    any help really appreciated!

    cheers,

    daniel

    --
    Posted via http://www.ruby-forum.com/.
    tfdj, Apr 1, 2006
    #1
    1. Advertising

  2. tfdj

    Trans Guest

    It really has nothing to do with eval, your just setting a local
    variable.

    An unfortuate side effect of the setter notation is that it conflicts
    with local var setting. Local var setting wins out, so you have to use
    self as the reciever in order to tell ruby you mean the setter method.

    T.
    Trans, Apr 1, 2006
    #2
    1. Advertising

  3. tfdj

    tfdj Guest

    tfdj, Apr 1, 2006
    #3
  4. tfdj

    Mike Austin Guest

    Trans wrote:
    > It really has nothing to do with eval, your just setting a local
    > variable.
    >
    > An unfortuate side effect of the setter notation is that it conflicts
    > with local var setting. Local var setting wins out, so you have to use
    > self as the reciever in order to tell ruby you mean the setter method.
    >
    > T.


    Since you bring this up, there are a few more cases where implicit locals
    declaration causes unexpected behavior (if new to ruby that is):

    x = 10
    (1..10).each { |i| x = x + i } # x == 65
    x = 10
    (1..10).each { |i| x = i } # x == 10

    So if you're assigning x to itself in some way, it recognizes x in the
    enclosing scope, else it creates a new local. That's kind of a confusing rule.
    Also, what if I wanted the first example to create a local? How do I refer
    to the toplevel `x` in the second?

    I'd really like to see explicit locals declarations in Ruby, and this would all
    be solved by simply introducing `var` or `local`, as in `var x = 10`. Even if
    it was only optional, and invoked with -strict-locals, I think many people
    would be happy. Maybe I'll download the source and hack away to test it :)


    Mike
    Mike Austin, Apr 1, 2006
    #4
  5. tfdj

    Guest

    On Apr 1, 2006, at 2:13 PM, Mike Austin wrote:
    >
    > Since you bring this up, there are a few more cases where implicit
    > locals declaration causes unexpected behavior (if new to ruby that
    > is):
    >
    > x = 10
    > (1..10).each { |i| x = x + i } # x == 65
    > x = 10
    > (1..10).each { |i| x = i } # x == 10
    >
    > So if you're assigning x to itself in some way, it recognizes x in
    > the enclosing scope, else it creates a new local. That's kind of a
    > confusing rule. Also, what if I wanted the first example to
    > create a local? How do I refer to the toplevel `x` in the second?


    The 'x' in each of those blocks references the local variable 'x'
    defined outside the block.
    In neither case is a new local variable 'x' created within the
    block. In both cases a new
    local variable 'i' is created within the blocks and is only visible
    within the individual block.

    Here are the rules I use to understand local variable scope and blocks:

    1) Local variables *created* outside a block are visible inside the
    block.

    2) Local variables *created* inside a block are *not* visible outside
    the block.

    3) Block arguments behave like *local* variables *not* formal
    (method) arguments.


    If you combine 1 and 2 you see that block scope is sort of a one-way
    barrier. Code inside the block can see variables created outside the
    block but not the other way around.

    The third rule is the one that throws everyone because most
    programmers tend to think of block arguments as formal arguments that
    shadow any similarly named variables outside the block but this is
    incorrect (in Ruby). Block arguments behave like *local* variables
    so if a block argument has the same name as a variable in the
    enclosing scope then a new local variable is *not* created. On the
    other hand if there is no local variable in the enclosing scope with
    the same name then a new local variable *is* created and is only
    visible within the block (rule 2).

    I believe it is rule 3) that Matz is considering changing for Ruby 2.0


    Gary Wright
    , Apr 1, 2006
    #5
  6. --Apple-Mail-18-260058564
    Content-Transfer-Encoding: 7bit
    Content-Type: text/plain;
    charset=US-ASCII;
    delsp=yes;
    format=flowed


    On Apr 1, 2006, at 2:53 PM, wrote:

    > Here are the rules I use to understand local variable scope and
    > blocks:
    >
    > 1) Local variables *created* outside a block are visible inside the
    > block.
    >
    > 2) Local variables *created* inside a block are *not* visible
    > outside the block.
    >
    > 3) Block arguments behave like *local* variables *not* formal
    > (method) arguments.


    Good list!
    --Apple-Mail-18-260058564--
    Logan Capaldo, Apr 1, 2006
    #6
  7. tfdj

    Mike Austin Guest

    wrote:
    >
    > On Apr 1, 2006, at 2:13 PM, Mike Austin wrote:
    >>
    >> Since you bring this up, there are a few more cases where implicit
    >> locals declaration causes unexpected behavior (if new to ruby that is):
    >>
    >> x = 10
    >> (1..10).each { |i| x = x + i } # x == 65
    >> x = 10
    >> (1..10).each { |i| x = i } # x == 10
    >>
    >> So if you're assigning x to itself in some way, it recognizes x in the
    >> enclosing scope, else it creates a new local. That's kind of a
    >> confusing rule. Also, what if I wanted the first example to create
    >> a local? How do I refer to the toplevel `x` in the second?

    >
    > The 'x' in each of those blocks references the local variable 'x'
    > defined outside the block.
    > In neither case is a new local variable 'x' created within the block.
    > In both cases a new
    > local variable 'i' is created within the blocks and is only visible
    > within the individual block.
    >
    > Here are the rules I use to understand local variable scope and blocks:
    >
    > 1) Local variables *created* outside a block are visible inside the block.
    >
    > 2) Local variables *created* inside a block are *not* visible outside
    > the block.
    >
    > 3) Block arguments behave like *local* variables *not* formal (method)
    > arguments.
    >
    >
    > If you combine 1 and 2 you see that block scope is sort of a one-way
    > barrier. Code inside the block can see variables created outside the
    > block but not the other way around.
    >
    > The third rule is the one that throws everyone because most programmers
    > tend to think of block arguments as formal arguments that shadow any
    > similarly named variables outside the block but this is incorrect (in
    > Ruby). Block arguments behave like *local* variables so if a block
    > argument has the same name as a variable in the enclosing scope then a
    > new local variable is *not* created. On the other hand if there is no
    > local variable in the enclosing scope with the same name then a new
    > local variable *is* created and is only visible within the block (rule 2).
    >
    > I believe it is rule 3) that Matz is considering changing for Ruby 2.0


    Changing the hiding characteristics of formal arguments sounds like a good
    idea, but there's still a big problem of not being able to declare locals. For
    example, given the following:

    def test()
    a = 2
    Proc.new { Proc.new { a = 10 }.call() }.call()
    puts a
    end

    test() => 10

    Lexical closure are a very nice thing, but if I think I'm creating a local when
    in fact I'm modifying some value in the enclosing scope, then that's bad. I
    think shadowing a parameters is a lot less dangerous, and a warning can be
    printed when that happens. So the above would look like this:

    Proc.new { Proc.new { var a = 10 }.call() }.call()


    Mike
    Mike Austin, Apr 1, 2006
    #7
  8. tfdj

    Pit Capitain Guest

    Mike Austin schrieb:
    > Since you bring this up, there are a few more cases where implicit
    > locals declaration causes unexpected behavior (if new to ruby that is):
    >
    > x = 10
    > (1..10).each { |i| x = x + i } # x == 65
    > x = 10
    > (1..10).each { |i| x = i } # x == 10
    >
    > So if you're assigning x to itself in some way, it recognizes x in the
    > enclosing scope, else it creates a new local. That's kind of a
    > confusing rule. Also, what if I wanted the first example to create a
    > local? How do I refer to the toplevel `x` in the second?


    Mike, you're accessing the toplevel "x" in both cases:

    x = nil
    (1..10).each { |i| x = i } # x == 10

    Regards,
    Pit
    Pit Capitain, Apr 2, 2006
    #8
    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. Ralf W. Grosse-Kunstleve
    Replies:
    16
    Views:
    559
    Lonnie Princehouse
    Jul 11, 2005
  2. Ralf W. Grosse-Kunstleve
    Replies:
    18
    Views:
    579
    Bengt Richter
    Jul 11, 2005
  3. Ralf W. Grosse-Kunstleve
    Replies:
    2
    Views:
    389
    Dan Sommers
    Jul 12, 2005
  4. James Britt
    Replies:
    28
    Views:
    430
    Jim Weirich
    Nov 8, 2004
  5. Jason Lillywhite

    accessor methods for class methods

    Jason Lillywhite, Sep 5, 2008, in forum: Ruby
    Replies:
    3
    Views:
    131
    Jason Lillywhite
    Sep 6, 2008
Loading...

Share This Page