Ruby1.9 block scope

I could have sworn that one of the firm changes in ruby 1.9 was that
variables defined inside a block would also exist outside the block. But
when I try it:

1.times{ x=2 }
=> 1

x
NameError: undefined local variable or method `x’ for main:Object

Did I dream all that? If it wasn’t a dream, when and why was that change
reversed?

Daniel

I could have sworn that one of the firm changes in ruby 1.9 was that
variables defined inside a block would also exist outside the block

No, it’s the reverse. Take this:

x = 5
1.upto(10) { |i| x = i }
puts x

ruby1.8 prints “10”, ruby1.9 should print “5”.

James C. wrote:

ruby1.8 prints “10”, ruby1.9 should print “5”.
Actually you are confusing things a litte. In this case ruby1.9 prints
“10”. Only the block parameters are local to the block:

i = “a”
=> “a”
2.times{ |i| puts i }
0
1
=> 2
puts i
a

Which is nice, but not nearly as nice as having the variables assigned
inside the block available outside of it. These slides are quite old but
this was the original plan:
http://www.rubyist.net/~matz/slides/rc2003/mgp00012.html

And I seem to remember I experienced that behavior in 1.9 a few months
ago only. But not any more :frowning:

Hi,

In message “Re: ruby1.9 block scope”
on Mon, 29 Sep 2008 19:54:43 +0900, Daniel DeLorme
[email protected] writes:

|I could have sworn that one of the firm changes in ruby 1.9 was that
|variables defined inside a block would also exist outside the block. But
| when I try it:
|
| >> 1.times{ x=2 }
|=> 1
| >> x
|NameError: undefined local variable or method `x’ for main:Object
|
|Did I dream all that? If it wasn’t a dream, when and why was that change
|reversed?

I have once presented a plan to make it work so, but have never
implemented. So it’s not “changed reversed”. Just the idea
abandoned.

          matz.

Yukihiro M. wrote:

|
|Did I dream all that? If it wasn’t a dream, when and why was that change
|reversed?

I have once presented a plan to make it work so, but have never
implemented. So it’s not “changed reversed”. Just the idea
abandoned.

Ah, ok, then I guess I did dream the whole thing. For the record, I
think it’s a great idea and deserves to be implemented… in ruby 2.0
maybe :wink:

Hi,

In message “Re: ruby1.9 block scope”
on Mon, 29 Sep 2008 21:24:02 +0900, Daniel DeLorme
[email protected] writes:

|> | >> 1.times{ x=2 }
|> |=> 1
|> | >> x
|> |NameError: undefined local variable or method `x’ for main:Object

|> I have once presented a plan to make it work so, but have never
|> implemented. So it’s not “changed reversed”. Just the idea
|> abandoned.
|
|Ah, ok, then I guess I did dream the whole thing. For the record, I
|think it’s a great idea and deserves to be implemented… in ruby 2.0
|maybe :wink:

My vague idea for the issue is that when you see the reference to a
local variable inside of the block, the scope of the variable would be
upgraded to the level of the reference.

          matz.

Daniel DeLorme wrote:

Yukihiro M. wrote:

upgraded to the level of the reference.
Do you mean upgrade the scope of the variable dynamically? Is that even
possible? I thought that all local vars had their scope pretty much set
in stone at the lexical level. But if you could upgrade their scoping
level dynamically… that would be nifty indeed!

If he did that , we wouldn’t have locals anymore .

Yukihiro M. wrote:

upgraded to the level of the reference.
Do you mean upgrade the scope of the variable dynamically? Is that even
possible? I thought that all local vars had their scope pretty much set
in stone at the lexical level. But if you could upgrade their scoping
level dynamically… that would be nifty indeed!

Hi,

At Tue, 30 Sep 2008 00:23:17 +0900,
Daniel DeLorme wrote in [ruby-talk:316347]:

My vague idea for the issue is that when you see the reference to a
local variable inside of the block, the scope of the variable would be
upgraded to the level of the reference.

Do you mean upgrade the scope of the variable dynamically? Is that even
possible? I thought that all local vars had their scope pretty much set
in stone at the lexical level. But if you could upgrade their scoping
level dynamically… that would be nifty indeed!

I guess the parser would do it at the compile time.

On Sep 29, 12:23 pm, Daniel DeLorme [email protected] wrote:

local variable inside of the block, the scope of the variable would be
upgraded to the level of the reference.

Do you mean upgrade the scope of the variable dynamically? Is that even
possible? I thought that all local vars had their scope pretty much set
in stone at the lexical level. But if you could upgrade their scoping
level dynamically… that would be nifty indeed!

Yeah, that would be so… 1970’s!

Even javascript seems to finally have abandoned dynamic scoping in
favor of friggin’ ALGOL’s lexical scoping… I wonder why would ruby
insist on sloppy programming by opening this old can of worms…

Nobuyoshi N. wrote:

I guess the parser would do it at the compile time.

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

The best I could think of was that a variable shouldn’t be upgraded if
the enclosing scope is a “class” or “module” section. That can be
detected at parse time so it would work with lexical binding.

But it would be very interesting indeed if you could bind a block’s
variables to the enclosing scope dynamically. You could say:
block.call_using_enclosing_scope #e.g. define_method
block.call_using_own_scope #e.g. each

To me that feels very very powerful. And more power to the programmer is
good, right? :wink:

Hi,

At Tue, 30 Sep 2008 09:10:39 +0900,
Daniel DeLorme wrote in [ruby-talk:316386]:

class Foo
define_method :bar do |;x|
x = 1 #I don’t want x to be defined in the Foo scope
end
define_method :baz do |;x|

namekuseijin wrote:

Yeah, that would be so… 1970’s!

Even javascript seems to finally have abandoned dynamic scoping in
favor of friggin’ ALGOL’s lexical scoping… I wonder why would ruby
insist on sloppy programming by opening this old can of worms…

Hehe, you have somewhat of a point. Local variables and proper isolation
of scope are pretty important to structured programming. But we
weren’t talking about a free-for-all opening of all scopes, just about
the scope of local variables within blocks. I wouldn’t much like my
method-local variables to creep into the global scope just because I
forgot to define them with “var”, no thank you.

Yukihiro M. 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?

Hi,

In message “Re: ruby1.9 block scope”
on Tue, 30 Sep 2008 09:10:39 +0900, Daniel DeLorme
[email protected] 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.

Hi,

In message “Re: ruby1.9 block scope”
on Tue, 30 Sep 2008 16:49:19 +0900, Mike G.
[email protected] writes:

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

|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?

Understandable. That’s the very reason the current Ruby does not work
like this.

          matz.

Yukihiro M. wrote:

Hi,

In message “Re: ruby1.9 block scope”
on Tue, 30 Sep 2008 16:49:19 +0900, Mike G.
[email protected] writes:

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

|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?

Understandable. That’s the very reason the current Ruby does not work
like this.

          matz.

The current ruby doesn’t, but a future one might? The reason I posted
was because the phrase “I haven’t introduced it yet” might imply that it
could happen.

Hi,

In message “Re: ruby1.9 block scope”
on Tue, 30 Sep 2008 17:24:03 +0900, Mike G.
[email protected] writes:

|The current ruby doesn’t, but a future one might? The reason I posted
|was because the phrase “I haven’t introduced it yet” might imply that it
|could happen.

Yes, it could happen, but not for sure. This idea revisit me
everytime I see “undefined local variable or method” error.

          matz.

Mike G. 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.

Hi –

On Tue, 30 Sep 2008, Yukihiro M. wrote:

| defined_method :bar do
variables at the same level, with a same name. See the following
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 :slight_smile: 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