Parameter in a block is not local?

I thought a iterator with a block is like an nameless function call…
so if it is a function call, the parameter is local.
but for the following, the output is surprising:

a = 1
p a

1.upto(10) {|a| p a}

p a


E:>ruby test_iterator.rb
1
1
2
3
4
5
6
7
8
9
10
10

a is changed!

but is it true that the “a” is not global to begin with…
but then, isn’t the “a” inside the block more local than the “a”
outside?

like in Pascal, i think there can be nested functions and therefore,
there will be local and then “local that is more local” than the outer
local.

SpringFlowers AutumnMoon wrote:

I thought a iterator with a block is like an nameless function call…
so if it is a function call, the parameter is local.
but for the following, the output is surprising:

Reread pickaxe2, p.51, second paragraph.

SpringFlowers AutumnMoon wrote:

I thought a iterator with a block is like an nameless function call…
so if it is a function call, the parameter is local.
but for the following, the output is surprising:

Also, I think I recall reading a post by Matz somewhere where he
shouldered the blame for that “feature” and said it was a design
mistake.

Hi –

On Sun, 14 Oct 2007, SpringFlowers AutumnMoon wrote:

7
8
9
10
10

a is changed!

but is it true that the “a” is not global to begin with…
but then, isn’t the “a” inside the block more local than the “a”
outside?

a is local, not global. The semantics of block parameters is
assignment semantics:

|a|

basically means “a = …”, in the same scope as the scope in which the
block is created. Blocks are different in that respect from methods,
and the || notation (instead of (), as in methods) is a good reminder
that they’re not the same. (Not that || specifically implies
assignment semantics, but it’s a reminder that there’s a difference.)

David

On Oct 14, 2007, at 8:42 AM, SpringFlowers AutumnMoon wrote:

I thought a iterator with a block is like an nameless function call…
so if it is a function call, the parameter is local.
but for the following, the output is surprising:

a = 1
p a

1.upto(10) {|a| p a}

p a

one way to think about it (not entirely correct) is this

  • if the parameter exists already it is reused
  • if not a block local var is created

this

1.upto(10){|a| p a}

p a

will throw an error - as you probably know. it’s a fine line between
having function call semantics and closure ones. we all want this to
work

message = ‘hello world’
42.times{ p message }

of course. so it’s rather tricky. you can search the archives but i
think the new rule is that introducing a var like so

method{ |some_var| …

will introduce a block local var (as you are expecting above), while
this

method{ p some_var

will not. i could be confused on this though, it really gets
confusing to not violate POLS (referring to mine here) in all cases

eigenclass.org
http://www.davidflanagan.com/blog/2007_08.html#000137

and, of course, search the archives - matz has spelled out the
changes several times.

kind regards.

a @ http://codeforpeople.com/

On Mon, 15 Oct 2007, David A. Black wrote:

a is local, not global. The semantics of block parameters is
assignment semantics:

|a|

basically means “a = …”, in the same scope as the scope in which the
block is created.

I should amend that by noting that it’s a “one-way valve”: if the
variable exists before the block is created, the scope is flat,
whereas if the variable doesn’t exist yet, it also doesn’t exist when
the block exits.

In other words, the local scope enters the block, from the left, so to
speak, bringing all its bindings with it; and it exits from the right
with only those bindings, which may or may not have been altered
during their time in the block.

David

On 10/14/07, SpringFlowers AutumnMoon [email protected] wrote:

7

like in Pascal, i think there can be nested functions and therefore,
there will be local and then “local that is more local” than the outer
local.

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

This seems to me along the same lines as

a = 1
if true
a = 10
end
p a # => 10

Which certainly is not surprising or unwelcome.

Pat

SpringFlowers AutumnMoon wrote:

a = 1
p a

1.upto(10) {|a| p a}

p a


E:>ruby test_iterator.rb
1
1
2
3
4
5
6
7
8
9
10
10

a is changed!

!Remark only!

There will be a change for soon upcoming Ruby 1.9.1:

irb(main):001:0> a = 1
=> 1
irb(main):002:0> p a
1
=> nil
irb(main):003:0> 1.upto(10) {|a| p a}
1
2
3
4
5
6
7
8
9
10
=> 1
irb(main):004:0> p a
1
=> nil

Wolfgang Nádasi-Donner

On 10/14/07, SpringFlowers AutumnMoon [email protected] wrote:

I thought a iterator with a block is like an nameless function call…

Similar, but not the same. Blocks are closures, so for example:

a = 1
1.times {p a}

will print 1 since a in the block refers to a in the outer scope.


8
9
10
10

a is changed!

but is it true that the “a” is not global to begin with…
but then, isn’t the “a” inside the block more local than the “a”
outside?

In Ruby 1.8 a block argument acts like a local in the containing scope.

This is changing in 1.9

http://eigenclass.org/hiki/Changes+in+Ruby+1.9#l8


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Pat M. wrote:

This seems to me along the same lines as

a = 1
if true
a = 10
end
p a # => 10

Which certainly is not surprising or unwelcome.

when compared to the following it is surprising:

a = 1
p a

def foo(a)
p a
end

for i in 1…10
foo(i)
end

p a


E:>ruby test_iterator2.rb
1
1
2
3
4
5
6
7
8
9
10
1

SpringFlowers AutumnMoon wrote:

I don’t know what software install Ruby 1.9 on my computer

C:\Users\Mike\ruby-1.9.0-20060415-i386-mswin32

This is a very old version of Ruby 1.9. Please don’t forget that Ruby
1.9(.0) is still an experimental version, that will move towards the
final Ruby 1.9.1 in December 2007 (I hope “December 2007” is the correct
date).

There are newer precompiled versions
(ruby-1.9.0-20070709-x64-mswin64_80.zip on
http://dl.ambiweb.de/mirrors/ftp.ruby-lang.org/binaries/mswin32/) or
snapshots which can be compiled (snapshot.tar.gz on
ftp://ftp.ruby-lang.org/pub/ruby/).

Wolfgang Nádasi-Donner

On 10/14/07, SpringFlowers AutumnMoon [email protected] wrote:

foo(i)
3
4
5
6
7
8
9
10
1

Well, that’s kind of the point of blocks, isn’t it? They close over
any vars that are currently in scope. Methods on the other hand have
their own scope. I guess it could be confusing if you thought methods
and blocks were the same thing…but, um, they’re not.

Pat

Hi –

On Mon, 15 Oct 2007, SpringFlowers AutumnMoon wrote:

foo(i)
3
4
5
6
7
8
9
10
1

There’s no relation or connection between the two. The def keyword
always starts a new local scope; the if keyword doesn’t. There’s no
reason to expect them to behave the same way as each other, as they
serve entirely different purposes.

David

Rick Denatale wrote:

This is changing in 1.9

eigenclass.org

I don’t know what software install Ruby 1.9 on my computer

C:\Users\Mike\ruby-1.9.0-20060415-i386-mswin32

and then if I run ruby 1.9, it gives me the same result:

C:\Users\Mike\ruby-1.9.0-20060415-i386-mswin32\bin>ruby test_iterator.rb
1
1
2
3
4
5
6
7
8
9
10
10
“==========”
“1.9.0”


Code

a = 1
p a

1.upto(10) {|a| p a}

p a

p “=” * 10

p RUBY_VERSION

David A. Black wrote:

Hi –

On Mon, 15 Oct 2007, SpringFlowers AutumnMoon wrote:

foo(i)
3
4
5
6
7
8
9
10
1

There’s no relation or connection between the two. The def keyword
always starts a new local scope; the if keyword doesn’t. There’s no
reason to expect them to behave the same way as each other, as they
serve entirely different purposes.

So in a way, think of a code block like a “if” statement? (no new local
scope)

Come to think about it, since

[1,2,3,4,5].each {|a| p a}

is equivalent to

for a in [1,2,3,4,5]
p a
end

so the “for” version clearly doesn’t have a new scope for “a”.

But in the newest Ruby 1.9, they are not equivalent any more?

SpringFlowers AutumnMoon wrote:

p a
end

so the “for” version clearly doesn’t have a new scope for “a”.

But in the newest Ruby 1.9, they are not equivalent any more?

No, they aren’t the same even in Ruby 1.8.x either. With the do…end or
{…} syntax, any variables assigned in the block, but inexisting at the
point of the definition of the block, are actually local to the block.

AFAIK, in 1.9, the formal parameters of the block, specified between
||'s, are considered unconditionally block-local too. In 1.8.x, those
are treated like any other local variables in the block: they refer to
the same as the enclosing block if pre-existing, and refer to
block-local variables otherwise.

mortee

mortee wrote:

But in the newest Ruby 1.9, they are not equivalent any more?

No, they aren’t the same even in Ruby 1.8.x either. With the do…end or
{…} syntax, any variables assigned in the block, but inexisting at the
point of the definition of the block, are actually local to the block.

I should have pointed out specifically the difference to the for … in
… end syntax: any local variable created (assigned to) in the latter
construct become part of the enclosing context, so you can actually
create new local variables in such a loop for later use.

mortee

SpringFlowers AutumnMoon wrote:

foo(i)
3
4
5
6
7
8
9
10
1

Yes, the def syntax specifically doesn’t take the caller binding, AFAIK.
If you intend having methods access variables local to where they are
defined, just use define_method, which takes a block, with all of its
peculiarities, like taking the caller binding along with its local
variables.

mortee

Hi –

On Mon, 15 Oct 2007, SpringFlowers AutumnMoon wrote:

6

So in a way, think of a code block like a “if” statement? (no new local
scope)

I think the best thing is to learn about blocks as blocks, and don’t
worry too much about how much they are or aren’t similar to other
things. A block has the variables from the local scope in which it was
created, and can also create its own variables, but the ones it
creates exist only inside the block. An if statement is truly flat
with regard to its local scope.

David

SpringFlowers AutumnMoon wrote:

I thought a iterator with a block is like an nameless function call…

Here’s another example(a modification of the example found in pickaxe2,
p 106):

if false
data = “hello”
end

(1…3).each {data = “goodbye”}

puts data

–output:–
goodbye

That is equivalent to Java’s call by value–but using references and C++
reference semantics, and the flat scope is converted to spheric scope
with assignment semantics applying throughout any call by value passing.
:slight_smile: