Reputation: 41
If I do this
x = y = z = 1
z = 20
then I get
"#{x}----#{y}----#{z}"
# => "1----1----20"
Now, if I do something like this:
a = b = c = []
then I get this:
"#{a}-----#{b}-----#{c}"
# => "[]-----[]-----[]"
But if I do the following:
c[0] = 'a'
c[1] = 'b'
c[2] = 'c'
I get this:
"#{a}-----#{b}-----#{c}"
# => "[\"a\", \"b\", \"c\"]-----[\"a\", \"b\", \"c\"]-----[\"a\", \"b\", \"c\"]"
In case of x
, y
, z
, when I assigned z
to 20
, then x
and y
retained the value 1
. For Arrays
, even though I assigned value to c[]
only, the change was reflected in a
,b
. What is happening with the Array
s?
Upvotes: 1
Views: 149
Reputation: 80085
In Ruby you have methods which change it's object and methods which return new objects (the documentation of the method will mention this). Integers can not mutate: two will always be two. Playing around with the object_id may clear things up:
puts 1.object_id # 3
a = 1
puts a.object_id # 3
puts 20.object_id # 41
a = 20
puts a.object_id # 41
b = []
puts b.object_id # a number
b[1]=1 # mutating object
puts b.object_id # same number
b = b+[2] # the + method results in new object http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-2B
puts b.object_id # another number
Upvotes: 0
Reputation: 187164
Think of what objects are being assigned to what variables, after all a variable is simply a handle for an object. In ruby everything is an object, and variables are just how you interact with them.
So...
a = b = 1
This sets a
and b
to reference the same object. If I later say:
a = 2
Then I have set a
to reference a new object, which shouldn't affect b
at all, which is happily still 1
. The interpeter takes one simple step.
a
to the object 2
.But, following that logic:
a = b = []
Again, a
and b
reference the same object. An array this time. But now when we do this:
a[0] = 'hello'
We have a different scenario here. You aren't changing what object a
references at all. You are finding the object a
references and then modifying that object.
Think about what the interpreter will do. It will take the following steps when executing that line.
a
(which happens to be the same object referenced by b
)0
index of that object to the string "hello"
All this is to say that simple local variable assignment like:
a = 1
Is a somewhat different operation when there is a layer of indirection present like these:
a[0] = 'hello'
a.foo = 'bar'
a.set_value 'some val'
Or think of setting a value in an array like calling a method on that array. So the difference becomes easier to grasp if you think of a[0] = 'foo'
as:
a.set_value(0, 'foo')
Something like this is actually what happens in ruby arrays. Turns out assigning a value to an array index calls the []=(index, value)
method. These are all valid and equivalent.
a[0] = 'foo'
a.[]=(0, 'foo')
a.send('[]=', 0, 'foo')
I point this out only because when expressed as an invocation of a method it becomes very clear we are modifying an existing object here.
Upvotes: 1
Reputation: 160893
With z = 20
, you are change z
to reference another object,
With c[0] = 'a'
, you are changing the original object which a
and b
is also referencing to.
Upvotes: 1