Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope of a local variable in a block

If I have:

2.times do
  i ||= 1
  print "#{i} "
  i += 1
  print "#{i} "
end

I get 1 2 1 2, whereas I was expecting 1 2 2 3. Why does i lose its assignment when the loop starts over? It behaves as expected if the assignment occurs outside the loop, so I guess it has to do with scope, but I didn't realize loops have their own scopes. Can someone clarify?

Update: Thanks for the help on this. Part of my confusion stemmed from coming to Ruby from Python, which doesn't have block scope (I think).

like image 813
ivan Avatar asked May 15 '13 17:05

ivan


People also ask

Where is the scope of local variable?

In Java, the scope of a local variable is the body of the method in which it is declared. In other words, the variable is visible in the body of the method where its declaration appears, but it is not visible on the outside the method.

What is scope of local variable in a class?

The scope of local variables always remains inside constructor, method, and block. It can not be accessible from outside the constructor, method, and block. 3. The scope of instance variables is within the class.

What is the scope of local variable explain with example?

Example 1: Local Scope Variable In the above program, variable a is a global variable and variable b is a local variable. The variable b can be accessed only inside the function greet . Hence, when we try to access variable b outside of the function, an error occurs.

What is the scope of a local variable C++?

The scope of a variable is the area of the program where the variable is valid. A global variable is valid from the point it is declared to the end of the program. A local variable's scope is limited to the block where it is declared and cannot be accessed (set or read) outside that block.


4 Answers

I don't know what your expectations are based on. If you think what I think you think, it should be 1 2 2 3. You can achieve that by declaring variable i outside of the block.

i = nil

2.times do
  i ||= 1
  print "#{i} "
  i += 1
  print "#{i} "
end

Then the block closes over that variable (closure) and uses it. Without closure, i is local to the block and is new every time.

like image 84
Sergio Tulentsev Avatar answered Sep 21 '22 16:09

Sergio Tulentsev


Look at the code below:

2.times do
  p defined? i
  i ||= 1
  p defined? i
  p "#{i} "
  i += 1
  p "#{i} "
end

Output:

nil 
"local-variable"
"1 "
"2 "
nil
"local-variable"
"1 "
"2 "

That means in each iteration a new scope is created,and i is known to that scope only; which is proved by nil and "local-variable".

Now i is created outside of block, and see the output(no nil comes):

i = nil
2.times do
  p defined? i
  i ||= 1
  p defined? i
  p "#{i} "
  i += 1
  p "#{i} "
end

Output:

"local-variable"
"local-variable"
"1 "
"2 "
"local-variable"
"local-variable"
"2 "
"3 "

To know more about ||= look What Ruby’s ||= (Double Pipe / Or Equals) Really Does

like image 41
Arup Rakshit Avatar answered Sep 19 '22 16:09

Arup Rakshit


It isn't the "loop" that has a scope. It's the block. Yes, a block is a local scope.

If you do not want a variable to be understood as local to the block, it needs to exist outside the block beforehand. Even just setting i to nil in a preceding line would do this.

(But your expectation of 1 2 3 4 will still not quite be met...!)

like image 41
matt Avatar answered Sep 20 '22 16:09

matt


You can have some fun with it. Say for example you want to access the scope inside the block.

block = -> do
  x = "Hello from inside a block"
  binding # return the binding
end

p defined? x              #=> nil
x = eval "x", block.call  #=> #<Binding:0x007fce799c7dc8>
p defined? x              #=> "local-variable"
p x                       #=> "Hello from inside a block"

This is important because it allows developers to basically blow away the encapsulation of a block, and should be used with caution.

like image 29
Nathan Lilienthal Avatar answered Sep 20 '22 16:09

Nathan Lilienthal