Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Eval needs explicit self for accessor methods?

Reply
Thread Tools

Eval needs explicit self for accessor methods?

 
 
tfdj
Guest
Posts: n/a
 
      04-01-2006
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/.


 
Reply With Quote
 
 
 
 
Trans
Guest
Posts: n/a
 
      04-01-2006
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.

 
Reply With Quote
 
 
 
 
tfdj
Guest
Posts: n/a
 
      04-01-2006
Of course! Thank you! Sorry for the dumb question. Makes perfect sense
now..

dl

--
Posted via http://www.ruby-forum.com/.


 
Reply With Quote
 
Mike Austin
Guest
Posts: n/a
 
      04-01-2006
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
 
Reply With Quote
 
gwtmp01@mac.com
Guest
Posts: n/a
 
      04-01-2006

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





 
Reply With Quote
 
Logan Capaldo
Guest
Posts: n/a
 
      04-01-2006
--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, http://www.velocityreviews.com/forums/(E-Mail Removed) 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--


 
Reply With Quote
 
Mike Austin
Guest
Posts: n/a
 
      04-01-2006
(E-Mail Removed) 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
 
Reply With Quote
 
Pit Capitain
Guest
Posts: n/a
 
      04-02-2006
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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing self: if self is a tree how to set to a different self Bart Kastermans Python 6 07-13-2008 11:19 AM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) falcon Python 0 07-31-2005 05:41 PM
Re: __autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 2 07-12-2005 03:20 AM
Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code Ralf W. Grosse-Kunstleve Python 16 07-11-2005 09:28 PM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 18 07-11-2005 04:01 PM



Advertisments