A Fresh Cup is Mike Gunderloy's software development weblog, covering Ruby on Rails and whatever else I find interesting in the universe of software. I'm a full-time Rails developer and contributor, available for long- or short-term consulting, with solid experience in working as part of a distributed team. If you'd like to hire me, drop me a line. I'm also the author of Rails Rescue Handbook and Rails Freelancing Handbook.

Navigation
« Double Shot #357 | Main | Double Shot #356 »
Tuesday
23Dec2008

Multi-variable Initialization Gotcha

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.

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.

December 23, 2008 | Unregistered CommenterNathan

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

December 23, 2008 | Unregistered CommenterFred

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

December 24, 2008 | Unregistered CommenterHenrik N

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.

December 24, 2008 | Unregistered CommenterMike Gunderloy

@Henrik: Ruby, Java, and C have pass-by-value semantics. Perl has pass-by-reference semantics.

December 26, 2008 | Unregistered CommenterXavier Noria

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

January 5, 2009 | Unregistered CommenterDoug

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>