When working with Ruby, you might come across some unexpected behavior when using Array.new with a block. This can lead to confusion and bugs that are hard to track down. Let’s explore a common pitfall and how to avoid it.

Consider the following code snippet:

a = Array.new(3) { 'a' }
=> ["a", "a", "a"]
irb(main):022:0> a[0] << 'b'
=> "ab"
irb(main):023:0> a
=> ["ab", "a", "a"]

At first glance, it seems like we have created an array with three independent string elements. However, when we modify the first element by appending 'b', only the first element changes. This is the expected behavior because each element is a separate string object.

Now, let’s look at a different scenario:

a = Array.new(3, 'a')
=> ["a", "a", "a"]
irb(main):022:0> a[0] << 'b'
=> "ab"
irb(main):023:0> a
=> ["ab", "ab", "ab"]

In this case, modifying the first element affects all elements in the array. This happens because Array.new(3, 'a') creates an array with three references to the same string object. When we modify one element, all elements reflect the change.

How to Avoid This Pitfall

To avoid this issue, always use the block form of Array.new when you need independent objects:

a = Array.new(3) { 'a' }

This ensures that each element is a separate object, preventing unintended side effects when modifying elements.

Conclusion

Understanding the difference between Array.new(3, obj) and Array.new(3) { obj } is crucial for avoiding bugs in your Ruby code. Always be mindful of whether you need independent objects or shared references in your arrays.