"Hello"b = a #=> "Hello"b += "" name="description" /> "Hello"b = a #=> "Hello"b += "" />

Strange Feature? of Ruby Arrays


I came around this strange feature(?) of arrays in Ruby and it would be very helpful if someone could explain to me why they work the way they do.

First lets give an example of how things usually work.

a = "Hello" #=> "Hello" b = a #=> "Hello" b += " Goodbye" #=> "Hello Goodbye" b #=> "Hello Goodbye" a #=> "Hello"

Ok cool, when you use = it creats a copy of the object (this time a string).

But when you use arrays this happens:

a = [1,2,3] #=> [1,2,3] b = a #=> [1,2,3] b[1] = 5 #=> [1,5,3] b #=> [1,5,3] a #=> [1,5,3]

Now thats just strange. Its the only object I've found that doesn't get copied when using = but instead just creates a refrance to the original object.

Can someone also explain (there must be a method) for copying an array without having it point back to the original object?


Actually, you should re-examine your premise.

The string assignment is really b = b + " Goodbye". The b + " Goodbye" operation returns an entirely new string, so the <em>variable</em> b is pointing to a new object after the assignment.

But when you assign to an individual array element, you are not creating an entirely new array, so a and b continue to point to the same object, which you just changed.

If you are looking for a rationale for the mutating vs functional behavior of arrays, it's simple. There is nothing to be gained by modifying the string. It is most likely necessary to allocate new memory anyway, so an entirely new string is created.

But an array can be arbitrarily large. Creating a new array in order to change just one element could be hugely expensive. And in any case, an array is like any other composite object. Changing an individual attribute does not necessarily affect any other attributes.

And to answer your question, you can always do:

b = a.dup


What happends there is that ruby is treating the Array object by reference and not by value.

So you can see it as this:

b= [1,2,3] a= b --'b' Points to---> [1,2,3] <--'a' points t---

So as you can see both point to the same reference, that means that if you change anything in a it will be reflected on b.

As for your question on the copying the object you could use the Object#clone method to do so.


Try your Array case with a String:

a = "Hello" #=> "Hello" b = a #=> "Hello" b[1] = "x" #=> "x" b #=> "Hxllo" a #=> "Hxllo"

Strings and Arrays work the same way in this regard.

The key difference in the two cases, as you wrote them, is this:

b += " Goodbye"

This is syntactic shorthand for

b = b + " Goodbye"

which is creating a new string from b + " Goodbye" and then assigning that to b. The way to modify an existing string, rather than creating a new one, is

b << " Goodbye"

And if you plug that into your sequence, you'll see that it modifies both a and b, since both variables refer to the same string object.

As for deep copying, there's a decent piece about it here:

<a href="http://ruby.about.com/od/advancedruby/a/deepcopy.htm" rel="nofollow">http://ruby.about.com/od/advancedruby/a/deepcopy.htm</a>


  • Folder specific cucumber-reporting without parallel run?
  • IBM Rationale Clearcase label
  • In Swift, an efficient function that separates an array into 2 arrays based on a predicate
  • How to cryptographically verify web page requisites?
  • How to print Escape Sequence characters in Swift?
  • Expected consumption of open file descriptors in Hadoop 0.21.0
  • Delete rows matching substring with LIKE?
  • Does setting autocommit=0 within a transaction do anything?
  • Expression pattern of type 'String' cannot match values of type 'AVMetadataKey'
  • Why does updating a hash set to a variable update that variable?
  • Extracting individual digits from a float
  • mapping between two ontologies
  • Cannot invoke my method on the array type int[]
  • Lua: Line breaks in strings
  • Iron Router: How do I send data to the layout?
  • Python pickle not one-to-one: different pickles give same object
  • Roxygen error “Skipping invalid path”
  • Moving Android View and preventing onDraw to be called over and over again
  • C: Incompatible pointer type initializing
  • why xml file does not aligned properly after append the string in beginning and end of the file usin
  • why do I get the error when installing the gem 'pg'? [duplicate]
  • NHibernate Validation Localization with S#arp Architecture
  • FileReader+canvas image loading problem
  • Initializer list vs. initialization method
  • Control modification in presentation layer
  • Why value captured by reference in lambda is broken? [duplicate]
  • Spring Data JPA custom method causing PropertyReferenceException
  • Sails.js/waterline: Executing waterline queries in toJSON function of a model?
  • Regex thinks I'm nesting, but I'm not
  • Why ng-show works with ng-repeat but ng-if doesn't? [duplicate]
  • Fetching methods from BroadcastReceiver to update UI
  • Excel - Autoshape get it's name from cell (value)
  • Fill an image in a square container while keeping aspect ratio
  • How to apply VCL Styles to DLL-based forms in Inno Setup?
  • Weird JavaScript statement, what does it mean?
  • Rearranging Cells in UITableView Bug & Saving Changes
  • Windows forms listbox.selecteditem displaying “System.Data.DataRowView” instead of actual value
  • Change div Background jquery
  • Django query for large number of relationships
  • Reading document lines to the user (python)