# Block and method local variables

**URL:** <https://www.ruby-forum.com/t/block-and-method-local-variables/51596>\
**Category:** Ruby\
**Created:** [January 4, 2006, 12:54am UTC](https://www.ruby-forum.com/t/block-and-method-local-variables/51596 "2006-01-04T00:54:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![SSSISO-8859-1SQSDan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@SSSISO-8859-1SQSDan](https://www.ruby-forum.com/u/SSSISO-8859-1SQSDan)\
**Post date:** [January 4, 2006, 12:54am UTC](https://www.ruby-forum.com/t/block-and-method-local-variables/51596/1 "2006-01-04T00:54:48Z")

</div>

hello all,

consider follow code

irb(main):528:0\* def abc  
irb(main):529:1\> ppp=111  
irb(main):530:1\> puts ppp  
irb(main):531:1\> yield  
irb(main):532:1\> puts ppp  
irb(main):533:1\> ppp  
irb(main):534:1\> end  
=\> nil  
irb(main):536:0\> abc {}  
111  
111  
=\> 111  
irb(main):537:0\> abc { puts ppp }  
111  
NameError: undefined local variable or method `ppp' for main:Object from (irb):537 from (irb):537:in`abc’  
from (irb):537  
from :0  
irb(main):538:0\>  
irb(main):539:0\*  
irb(main):540:0\* ppp = “OOO”  
=\> “OOO”  
irb(main):541:0\> abc { puts ppp }  
111  
OOO  
111  
=\> 111  
irb(main):542:0\>

I am right assuming that all “local” variables in the method abc  
are invisible in the block?

I tried a little more

irb(main):544:0\* def cba  
irb(main):545:1\> ppp = 222  
irb(main):546:1\> puts ppp  
irb(main):547:1\> yield ppp  
irb(main):548:1\> puts ppp  
irb(main):549:1\> ppp  
irb(main):550:1\> end  
=\> nil  
irb(main):551:0\> cba {}  
222  
222  
=\> 222  
irb(main):552:0\> cba {|p|}  
222  
222  
=\> 222  
irb(main):553:0\> cba {|p| p = 333}  
222  
222  
=\> 222  
irb(main):554:0\> cba {|p| puts p; p = 333}  
222  
222  
222  
=\> 222  
irb(main):555:0\>

if explicitely passed to block ppp is now visible there.  
but seems to be imposible to change the “method local” variable  
ppp in this case.

the following _does_ work

irb(main):557:0\* def xxx  
irb(main):558:1\> ppp = [1]  
irb(main):559:1\> p ppp  
irb(main):560:1\> yield ppp  
irb(main):561:1\> p ppp  
irb(main):562:1\> ppp  
irb(main):563:1\> end  
=\> nil  
irb(main):564:0\> xxx {}  
[1]  
[1]  
=\> [1]  
irb(main):565:0\> xxx {|x| }  
[1]  
[1]  
=\> [1]  
irb(main):566:0\> xxx {|x| x[0]=2 }  
[1]  
[2]  
=\> [2]  
irb(main):567:0\>

and I kind of understand why it works

if I change line 566 to  
irb(main):566:0\> xxx {|x| x=[2] }  
than it would not work

the reason I came accross this is following  
I was reading

"  
Parameters to a block may be existing local variables; if so, the new  
value of the variable will be retained after the block completes. This  
may lead to unexpected behavior, but there is also a performance gain to  
be had by using variables that already exist  
"  
and in my understanding all variables defined in a method  
are “local” (C++ background)

If not local what are they considered to be then?

Regards, Daniel

---

<div class="post-metadata">

**Author:** ![SSSISO-8859-1SQSDan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@SSSISO-8859-1SQSDan](https://www.ruby-forum.com/u/SSSISO-8859-1SQSDan)\
**Post date:** [January 4, 2006, 2:30am UTC](https://www.ruby-forum.com/t/block-and-method-local-variables/51596/2 "2006-01-04T02:30:52Z")

</div>

Okay, I’m too tired…

On Wed, 04 Jan 2006 00:58:08 -0000, Ross B.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> They are local. I think that test is referring to this:  
> ^^^^  
> That should be ‘text’

> =\> nil
> 
> irb(main):026:0\> d = Demo.new  
> =\> #Demo:0xb7f49a6c  
> irb(main):027:0\> [‘one’,‘two’,‘three’].each { |d.last| }  
> =\> [“one”, “two”, “three”]  
> irb(main):028:0\> d.last   
> ^^^^  
> And that should be:

```
irb(main):028:0> d.all

```

> =\> [“one”, “two”, “three”]

That’ll teach me to refactor in Opera…

---

<div class="post-metadata">

**Author:** ![SSSISO-8859-1SQSDan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@SSSISO-8859-1SQSDan](https://www.ruby-forum.com/u/SSSISO-8859-1SQSDan)\
**Post date:** [January 4, 2006, 11:15am UTC](https://www.ruby-forum.com/t/block-and-method-local-variables/51596/3 "2006-01-04T11:15:29Z")

</div>

Daniel Schüle wrote:

> if I change line 566 to  
> irb(main):566:0\> xxx {|x| x=[2] }  
> than it would not work

Note, that you can use get the return value of the block from yield:

def foo  
p yield( 111 )  
end

> > foo {|x| x + 10}  
> > 121  
> > =\> nil

> are “local” (C++ background)
> 
> If not local what are they considered to be then?

They are local. Stress in the setence above must be on “existing”. It  
means a situation like this:

def get\_last(enum)  
last = nil  
enum.each {|last|}  
last  
end

> > get\_last [1,2,43,3,2,4]  
> > =\> 4

This works because “last” is defined before the block. This does not  
work:

def get\_last(enum)  
enum.each {|last|}  
last  
end

> > get\_last [1,2,43,3,2,4]  
> > NameError: undefined local variable or method `last' for main:Object from (irb):26:in`get\_last’  
> > from (irb):28  
> > from :0

IOW, if the variable is defined in the surrounding scope that is the one  
used. If it’s defined only in the block (either as parameter or in the  
body) it’s visibility is limited to the block. Note that this is how  
most  
PL do nested scoping.

/\* C _/  
int foo() {  
int x;  
{  
/_ x is visible here _/  
int y = x;  
}  
/_ no y visible here \*/  
}

Note, that the scope of block parameters may change in the future.  
There  
have been lengthy discussions about this but ATM I don’t remember the  
details.

Kind regards

```
robert
```

---

<div class="post-metadata">

**Author:** ![SSSISO-8859-1SQSDan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@SSSISO-8859-1SQSDan](https://www.ruby-forum.com/u/SSSISO-8859-1SQSDan)\
**Post date:** [January 4, 2006, 2:09am UTC](https://www.ruby-forum.com/t/block-and-method-local-variables/51596/4 "2006-01-04T02:09:39Z")

</div>

On Wed, 04 Jan 2006 00:46:16 -0000, Daniel SchÃ¼le  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> irb(main):534:1\> end  
> from (irb):537  
> irb(main):542:0\>
> 
> I am right assuming that all “local” variables in the method abc  
> are invisible in the block?

Yes. The block captures the scope it is defined in, not the scope it’s  
called from, i.e. it’s a closure.

> irb(main):551:0\> cba {}  
> =\> 222

Yes. Ignoring implementation details, the block parameter ‘p’ is given a  
reference to the same object. When you then assign to ‘p’ that reference  
is replaced by a new reference to the object you assigned. Note that  
this  
is only for ‘p’ - ‘ppp’ still has the same reference it always had (to  
the  
original object).

The reality is apparently slightly more complex but I believe that for  
most practical purposes (including this)you can ignore that.

> irb(main):564:0\> xxx {}  
> =\> [2]  
> irb(main):567:0\>
> 
> and I kind of understand why it works
> 
> if I change line 566 to  
> irb(main):566:0\> xxx {|x| x=[2] }  
> than it would not work

Correct. The original code doesn’t actually assign anything to ‘x’, but  
instead calls the []= method on it, which modifies the array’s content.  
Since both ‘ppp’ and ‘x’ reference the same Array instance, your change  
makes it out of the block.

In the second case, you _do_ assign to ‘x’, supplying a new array. ‘ppp’  
retains it’s original value, so the new array is (almost) lost.

Almost, because of course it’s not _quite_ lost at that point:

```
irb(main):001:0> def xxx
irb(main):002:1> ppp = [1]
irb(main):003:1> p ppp
irb(main):004:1> ppp = yield ppp
irb(main):005:1> p ppp
irb(main):006:1> end
=> nil
irb(main):007:0> xxx { |x| x = [2] }
[1]
[2]
=> nil

```

> are “local” (C++ background)
> 
> If not local what are they considered to be then?

They are local. I think that test is referring to this:

```
irb(main):017:0> def test(arg)
irb(main):018:1> p arg
irb(main):019:1> [1,2,3].select { |arg| arg % 2 == 0 }
irb(main):020:1> p arg
irb(main):021:1> end
=> nil
irb(main):022:0> test("ten")
"ten"
3
=> nil

```

An interesting aside to this (IMHO) is this:

```
irb(main):018:0> class Demo
irb(main):019:1> def last=(arg)
irb(main):020:2> (@last ||= []) << arg
irb(main):021:2> end
irb(main):022:1> def all
irb(main):023:2> @last
irb(main):024:2> end
irb(main):025:1> end
=> nil

irb(main):026:0> d = Demo.new
=> #<Demo:0xb7f49a6c>
irb(main):027:0> ['one','two','three'].each { |d.last| }
=> ["one", "two", "three"]
irb(main):028:0> d.last
=> ["one", "two", "three"]

```

Which I guess illustrates that block arguments are handled by assignment  
to the named variable (or method in this case), and should make more  
sense  
of the preceeding example…

Cheers,
