Reputation: 1833
array1 = [0, 1]
# CASE 1:
[array1].each do |arr|
arr = [3, 4]
end
=> [0, 1]
# CASE 2:
[array1].each do |arr|
arr.delete_if { |ele| ele == 0 }
end
=> [[1]]
I thought ruby always passes array by reference. Why didn't it change the value of array in CASE 1 but did change it in CASE 2? thanks.
Upvotes: 0
Views: 918
Reputation: 122489
.each
simply calls the block with each element of the collection it's called on (in this case [array1]
) in turn. Passing an argument just assigns it to a parameter. Your example can be simplified to the following:
# CASE 1:
array1 = [0, 1]
arr = array1
arr = [3, 4]
array1
=> [0, 1]
# CASE 2:
array1 = [0, 1]
arr = array1
arr.delete_if { |ele| ele == 0 }
array1
=> [1]
Upvotes: 0
Reputation: 9605
In your first situation, all you've done is change which object arr
points at - you haven't actually modified the original. This can be proven with the following script:
# Given our test value...
test_array = [1, 2]
# we can verify the values and the object_ids
puts "Value of `test_array`: #{test_array.inspect}"
puts "Object_id of `test_array`: #{test_array.object_id}"
# now, let's put it in a container and run it through a block
@array_container = [test_array]
@array_container.each do |arr|
# Just to prove that `arr` points at test_array
puts "Object_id of `arr`: #{arr.object_id}"
# and that it's the same as the first element in our container
puts "@container.first.object_id: #{@array_container.first.object_id}"
# but, when we re-assign our block variable
arr = [3, 4]
# we get different values
puts "Object_id of `arr`: #{arr.object_id}"
puts "@container.first.object_id: #{@array_container.first.object_id}"
end
Which outputs...
Value of `test_array`: [1, 2]
Object_id of `test_array` : 2150710260
Object_id of `arr` : 2150710260
@container.first.object_id: 2150710260
Object_id of `arr` : 2150708040
@container.first.object_id: 2150710260
So how is that different in Case 2? In case 2, you're actually calling a self-destructive method, which will make changes to the original object that is being referenced by arr
Upvotes: 2
Reputation: 6606
I think your issue has to do with scope. The do-end
construct is really a new block, so when you declare arr = [3, 4]
you are instantiating a new arr = [3, 4]
within that block. Whereas in Case 2 you are modifying the reference directly. To do the same thing in Case 1 would be something like:
[array1].each do |arr|
arr.each_index do |i|
arr[i]+=3
end
end
=> [[3,4]]
Upvotes: 0