Q1: What happens when you assign a new variable str
to a value of 'foo'
?
str = 'foo'
str.object_id # => 2000
A: A label called str
is created that points at the object 'foo'
, which for the state of this Ruby interpreter happens to be at memory location 2000
.
Q2: What happens when you assign the existing variable str
to a new object using =
?
str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002
A: The label str
now points to a different object.
Q3: What happens when you assign a new variable =
to str
?
str2 = str
str2.object_id # => 2002
A: A new label called str2
is created that points at the same object as str
.
Q4: What happens if the object referenced by str
and str2
gets changed?
str2.replace 'baz'
str2 # => 'baz'
str # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002
A: Both labels still point at the same object, but that object itself has mutated (its contents have changed to be something else).
How does this relate to the original question?
It's basically the same as what happens in Q3/Q4; the method gets its own private copy of the variable / label (str2
) that gets passed in to it (str
). It can't change which object the label str
points to, but it can change the contents of the object that they both reference to contain else:
str = 'foo'
def mutate(str2)
puts "str2: #{str2.object_id}"
str2.replace 'bar'
str2 = 'baz'
puts "str2: #{str2.object_id}"
end
str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004