Tuesday
23Dec2008
Multi-variable Initialization Gotcha
Tuesday, December 23, 2008 at 7:14AM
Sometimes the fact that I don't know all the ins and outs of Ruby, coupled with habits carried over from other languages, turns around to bite me. Here's a console session demonstration of the latest problem I had:
[sourcecode language='ruby']
>> a = b = 2
=> 2
>> a = 3
=> 3
>> b
=> 2
>> a = b = []
=> []
>> a << 2
=> [2]
>> b
=> [2]
>> a = []; b = []
=> []
>> a << 2
=> [2]
>> b
=> []
[/sourcecode]
So, trying to initialize multiple arrays and multiple integers doesn't work the same. Live and learn.
[sourcecode language='ruby']
>> a = b = 2
=> 2
>> a = 3
=> 3
>> b
=> 2
>> a = b = []
=> []
>> a << 2
=> [2]
>> b
=> [2]
>> a = []; b = []
=> []
>> a << 2
=> [2]
>> b
=> []
[/sourcecode]
So, trying to initialize multiple arrays and multiple integers doesn't work the same. Live and learn.

Reader Comments (6)
I had the same problem with strings, since I was used to C# strings being immutable. I wound up scribbling all over one string because I initialized it from the same string constant as another string.
Well they do work the same in a way. In either case you will have a.object_id == b.object_id.
The difference is that a << 1 (where a is an array) mutates the array in place, whereas a = 3 just sets a to point to a new object. Integers are immutable, so you can't modify them and end up not doing what you intended
What Fred said. Ruby is pass-by-reference, but integers are immutable so effectively by-value. More details: http://www.ruby-forum.com/topic/41160
Yup, it all makes perfect sense. Just a warning to other developers who may be carrying over bad habits from Languages We Shall Not Name. Learning never ends.
@Henrik: Ruby, Java, and C have pass-by-value semantics. Perl has pass-by-reference semantics.
Actually they are working the same way. b is assigned a value and then a is assigned the same value from b.
In the case of the integers, the value is 2, so a and b both end up holding the value 2.
In the case of the array, the value is the reference to the array, not the array itself. So b is assigned a reference as a value, and a is then assigned the same reference. They both refer to the same array so any changes to the array are visible via both references.
Another way to look at it is to rewrite the code:
b = 2
a = b
What is the value of a?
b = []
a = b
And now?
The key is to understand that a = b = x is equivalent to these expanded examples, not:
b = x
a = x