[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Re: ruby1.9 block scope

Yukihiro Matsumoto

9/30/2008 4:14:00 AM

Hi,

In message "Re: ruby1.9 block scope"
on Tue, 30 Sep 2008 09:10:39 +0900, Daniel DeLorme <dan-ml@dan42.com> writes:

|That was also my guess; it least it's an easy concept to imagine. But it
|does bring the question of what to do when you *don't* want variables to
|"escape" into the enclosing scope? e.g.
|
|class Foo
| defined_method :bar do
| x = 1 #I don't want x to be defined in the Foo scope
| end
| defined_method :baz do
| x = 2 #because it would wind up shared with this method
| end
|end

As Nobu stated, you can explicitly declare block local variables,
using ';'. Besides that above code would not share variable x, since
the variable is not used upper level. They are two distinct
variables at the same level, with a same name. See the following
code, that makes a variables shared among blocks:

class Foo
defined_method :bar do
x = 1
end
defined_method :baz do
x = 2
end
x = 45 # this assignment would make x shared with foo and bar under the new rule.
end

The reason I haven't introduced it yet in Ruby is that single
assignment after the blocks can change the scope of a variable
afterward. Same thing happens assignments _before_ the blocks
already. But I hesitated to enhance that far.

matz.

7 Answers

Mike Gold

9/30/2008 7:49:00 AM

0

Yukihiro Matsumoto wrote:
>
> As Nobu stated, you can explicitly declare block local variables,
> using ';'. Besides that above code would not share variable x, since
> the variable is not used upper level. They are two distinct
> variables at the same level, with a same name. See the following
> code, that makes a variables shared among blocks:
>
> class Foo
> defined_method :bar do
> x = 1
> end
> defined_method :baz do
> x = 2
> end
> x = 45 # this assignment would make x shared with foo and bar under
> the new rule.
> end
>
> The reason I haven't introduced it yet in Ruby is that single
> assignment after the blocks can change the scope of a variable
> afterward. Same thing happens assignments _before_ the blocks
> already. But I hesitated to enhance that far.
>
> matz.

Making the scope of x contingent upon what comes later would result, I
believe, in extreme confusion.

Let's say Foo is a large class. Joe Schmo, who did not write Foo, comes
along and adds some code to the bottom, such as the 'x = 45' in your
example. Suddenly there is a bug in Foo. It seems impossible to Joe,
but there it is. He wonders if it is caused by the recent sunspots. He
wraps his computer in tin foil, but to no avail. The tests for bar and
baz still fail as a result of his (obviously, to him) unrelated change.

This was the 'tall' case, but there is also the 'wide' case of deeply
nested scopes. An equal helping of confusion applies here too.

One might argue that when 'x = 45' appears before bar and baz, this
_already_ changes the meaning of bar and baz. But the situation here is
entirely different, in my mind. Don't most of us read code from top to
bottom?

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

Daniel DeLorme

9/30/2008 8:56:00 AM

0

Mike Gold wrote:
> Making the scope of x contingent upon what comes later would result, I
> believe, in extreme confusion.
>
> Let's say Foo is a large class. Joe Schmo, who did not write Foo, comes
> along and adds some code to the bottom, such as the 'x = 45' in your
> example. Suddenly there is a bug in Foo. It seems impossible to Joe,
> but there it is. He wonders if it is caused by the recent sunspots. He
> wraps his computer in tin foil, but to no avail. The tests for bar and
> baz still fail as a result of his (obviously, to him) unrelated change.
>
> This was the 'tall' case, but there is also the 'wide' case of deeply
> nested scopes. An equal helping of confusion applies here too.
>
> One might argue that when 'x = 45' appears before bar and baz, this
> _already_ changes the meaning of bar and baz. But the situation here is
> entirely different, in my mind. Don't most of us read code from top to
> bottom?

Yes, I would argue that, and I believe most of us don't *add* new code
always at the bottom of the file. If the bar and baz methods are defined
at the bottom and Joe Schmo adds x = 45 at the top, he has the same
problem. I really don't see how it's any different; it's symmetric. Bugs
happen, and it's possible to come up with "problems cases" for
absolutely every feature in ruby, but that doesn't mean they turn out to
be problems in reality.

I must ask: is this confusing to *you* or are you trying to "protect" a
hypothetical Joe Schmo? I'll take the hypothetically confused Joe Schmo
over the very *real* confusion of every ruby newbie who wonders why his
local var has disappeared after the loop.

--
Daniel

David A. Black

9/30/2008 9:41:00 AM

0

Hi --

On Tue, 30 Sep 2008, Yukihiro Matsumoto wrote:

> Hi,
>
> In message "Re: ruby1.9 block scope"
> on Tue, 30 Sep 2008 09:10:39 +0900, Daniel DeLorme <dan-ml@dan42.com> writes:
>
> |That was also my guess; it least it's an easy concept to imagine. But it
> |does bring the question of what to do when you *don't* want variables to
> |"escape" into the enclosing scope? e.g.
> |
> |class Foo
> | defined_method :bar do
> | x = 1 #I don't want x to be defined in the Foo scope
> | end
> | defined_method :baz do
> | x = 2 #because it would wind up shared with this method
> | end
> |end
>
> As Nobu stated, you can explicitly declare block local variables,
> using ';'. Besides that above code would not share variable x, since
> the variable is not used upper level. They are two distinct
> variables at the same level, with a same name. See the following
> code, that makes a variables shared among blocks:
>
> class Foo
> defined_method :bar do
> x = 1
> end
> defined_method :baz do
> x = 2
> end
> x = 45 # this assignment would make x shared with foo and bar under the new rule.
> end
>
> The reason I haven't introduced it yet in Ruby is that single
> assignment after the blocks can change the scope of a variable
> afterward. Same thing happens assignments _before_ the blocks
> already. But I hesitated to enhance that far.

Please continue to hesitate :-) That would be very hard to deal with.
As a reader of the code, you'd have to do a two-pass visual scan
before you could begin to understand any of it. And you would have to
do that for *every* block, just in case, even if only 1% of them had a
variable defined later.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.r... for details and updates!

Daniel DeLorme

9/30/2008 2:46:00 PM

0

David A. Black wrote:
>
> On Tue, 30 Sep 2008, Yukihiro Matsumoto wrote:
>
>> The reason I haven't introduced it yet in Ruby is that single
>> assignment after the blocks can change the scope of a variable
>> afterward. Same thing happens assignments _before_ the blocks
>> already. But I hesitated to enhance that far.
>
> Please continue to hesitate :-) That would be very hard to deal with.
> As a reader of the code, you'd have to do a two-pass visual scan
> before you could begin to understand any of it. And you would have to
> do that for *every* block, just in case, even if only 1% of them had a
> variable defined later.

You dont need a two-pass visual scan; it just allows you to assume that
a variable defined a line L of a method will be available for reference
at line L+n, no matter if it was defined inside a block or not. It
should be common sense, really.

--
Daniel

Mike Gold

9/30/2008 2:52:00 PM

0

Daniel DeLorme wrote:
> Mike Gold wrote:
>> This was the 'tall' case, but there is also the 'wide' case of deeply
>> nested scopes. An equal helping of confusion applies here too.
>>
>> One might argue that when 'x = 45' appears before bar and baz, this
>> _already_ changes the meaning of bar and baz. But the situation here is
>> entirely different, in my mind. Don't most of us read code from top to
>> bottom?
>
> Yes, I would argue that, and I believe most of us don't *add* new code
> always at the bottom of the file. If the bar and baz methods are defined
> at the bottom and Joe Schmo adds x = 45 at the top, he has the same
> problem. I really don't see how it's any different; it's symmetric. Bugs
> happen, and it's possible to come up with "problems cases" for
> absolutely every feature in ruby, but that doesn't mean they turn out to
> be problems in reality.
>
> I must ask: is this confusing to *you* or are you trying to "protect" a
> hypothetical Joe Schmo? I'll take the hypothetically confused Joe Schmo
> over the very *real* confusion of every ruby newbie who wonders why his
> local var has disappeared after the loop.

Joe Schmo is all of us. Like D. Black says, all of us would need to
read the code twice before understanding it. In practice it is probably
more common to read with backtracking, which is even slower.

On the other hand, a ruby newbie who first encounters the rules for
local variable bindings (in the form of an error) should in no manner be
shielded from understanding them. That error is an important learning
experience.

For old-timers like me who, coming from lisp, often use closures to
preserve state in conjunction with define_method on anonymous classes,
the impact of the proposed change is significant (or unmanageable,
depending on your point of view). It transforms code complexity from
O(n)--n nested blocks--to O(n^2)--n nested blocks (which can't even be
called "nested" anymore) with backtracking.
--
Posted via http://www.ruby-....

Mike Gold

9/30/2008 3:03:00 PM

0

Daniel DeLorme wrote:
> David A. Black wrote:
>> before you could begin to understand any of it. And you would have to
>> do that for *every* block, just in case, even if only 1% of them had a
>> variable defined later.
>
> You dont need a two-pass visual scan; it just allows you to assume that
> a variable defined a line L of a method will be available for reference
> at line L+n, no matter if it was defined inside a block or not. It
> should be common sense, really.

You have described exactly what D. Black and I mean by a two-pass scan.
Line L is dependent on code arbitrarily far ahead at L+n.

When you encounter the variable at line L+n, you should backtrack to
line L to determine whether or not the block scopes are aligned in such
a way to change the meaning of line L.
--
Posted via http://www.ruby-....

Mike Gold

9/30/2008 5:07:00 PM

0


I hope I'm not belaboring the point, but --

a = Class.new {
define_method(:f) {
x
}

define_method(:x) {
33
}
}.new

x = 44

b = Class.new {
define_method(:f) {
x
}

define_method(:x) {
55
}
}.new

p a.f # => 33
p b.f # => 44

You want a.f == 44. I do not.

If you think this is a contrived example then you haven't been exposed
to the elegant solution this gives for certain cases. At run-time we
are creating additional layers of abstraction which translate the
current context into pieces which are passed to lower levels.

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