'What is the specific difference between block variable and block-local variable in Ruby? [closed]
I have an example, there are 3 variables with the same name inside and outside the block, and if they are printed inside and outside the block, there will be different results. Here is the code:
x = y = z = 0
ary = [1, 2, 3]
ary.each do |x; y|
y = x
z = x
p [x, y, z]
end
puts
p [x, y, z]
the result of p [x, y, z] within the block
[1, 1, 1]
[2, 2, 2]
[3, 3, 3]
the result of p [x, y, z] outside the block
[0, 0, 3]
However, I am unable to understand some issues.
First of all, x and y in the first line of the block are both parameters inside the block and have nothing to do with things with the same name outside. The result is the same whether y is a block variable (, y) or a block-local variable (; y). why? Does this mean that block variables are not actually different from block-local variables?
Second, even if I remove the parameter "; y", the result of p [x, y, z] inside the block is still unchanged, while the result of p [x, y, z] outside the block becomes [ 0, 3, 3], why?
Third, the result of p [x, y, z] outside the block, why is z not 0? x, y, z are all assigned to 0 in the first line.
Solution 1:[1]
In my mind and unless I'm misunderstanding, this can all be simplified if you understand that any and all Block Parameters (|*parameters|) define variables that ONLY exist inside the block. In addition, Block Parameters will always be used as "block variables" (or "block arguments") and passed directly to the method UNLESS you specify otherwise by assigning them as "block-local variables" using |*block_variables; *block_local_variables| syntax, or by explicitly assigning values using either |x, y = value| or |x, y: value| syntax.
NOTE: Only one semicolon is required to specify any number of the aforementioned block-local variables. Everything after the semicolon is essentially being defined as a block-local and is NOT passed to the method.
The only reason for a block-local variable that I am aware of is to re-use a variable name without affecting the variable that exists outside the block.
Let's address your specific questions:
x and y in the first line of the block are both parameters inside the block and have nothing to do with things with the same name outside. The result is the same whether y is a block variable (, y) or a block-local variable (; y). why?
In your specific example the results might be the same, but consider this example:
x, y, z = 0,0,0
arr = [
[1, 2, 3],
[4, 5, 6]
]
arr.map {|x, y| y = x; z = x}
[x, y, z] #=> [0, 0, 4]
whereas;
arr.map {|x; y| y = x; z = x}
[x, y, z] #=> [0, 0, [4, 5, 6]]
even if I remove the parameter "; y", the result of p [x, y, z] inside the block is still unchanged, while the result of p [x, y, z] outside the block becomes [ 0, 3, 3], why?
Consider what happens if you modify your example to place the ; BEFORE your block variable:
x = y = z = 0
ary = [1, 2, 3]
ary.each do |;x|
y = x
z = x
p [x, y, z]
end
puts
p [x, y, z] #=> [0, nil, nil]
In that example, we told Ruby not to modify x outside the block and since x is no longer being passed to the method, is simply being assigned as a block-local variable, and is not being assigned a value, the resulting value of x inside the block is nil.
the result of p [x, y, z] outside the block, why is z not 0? x, y, z are all assigned to 0 in the first line.
z is not zero because you did not protect it as a block-local variable like you did with y. Consider this version though:
ary.each do |x; z|
y = x
z = x
end
puts
p [x, y, z] #=> [0, 3, 0]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
