TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Ruby: shallow copy surprise!

10 pointsby aarongoughabout 15 years ago

12 comments

tptacekabout 15 years ago
This is a <i>lot</i> of text and boilerplate for a very, very simple idea:<p><pre><code> &#62;&#62; x = [1,2,3] =&#62; [1, 2, 3] &#62;&#62; def go(z); z[1] = 0; end =&#62; nil &#62;&#62; go(x) =&#62; 0 &#62;&#62; x =&#62; [1, 0, 3] </code></pre> Mutable objects in Ruby are passed by reference, not value.
评论 #1364556 未加载
phaedrusabout 15 years ago
The Io language has a similar gotcha - when I cloned one of my prototypes that contained a List member, I was surprised to find that all the clones shared the same List! It actually makes sense - it was the reference to the list that was copied, but all the references pointed to the same list.<p>The problem with always defaulting to deep copy in a language where all object slots are by reference is "where do you stop?" Do you copy all the objects known to that object? If the object holds a data file or a resource, do you deep copy that too? What about object graphs? What about two objects mutually holding references to each other? What if the object holds a reference to the global application object?<p>So the most common way to do it is default to only a shallow copy. It's up to the user to define a deep copy if they need it because only the user knows what members are semantically "part of" the parent object and what are "pointers" to unowned objects.
tjarrattabout 15 years ago
I ran into the exact same problem when trying to solve some (not very complicated in retrospect) errors in a body of text. Shallow copying a string that I was applying permutations to and storing in an array meant that every single string in the array was the same, so I could never have more than one permutation without pulling some hacks like this.<p>I would be very interested in a cleaner variant on the marshal load hack for non-primitives, or even some interesting doc/writeup on how this works.
swivelmasterabout 15 years ago
Are you kidding me? The "solution" is to serialize and deserialize? That's a incredible waste.<p>edit: I thought it was not uncommon for higher level languages to pass arrays and objects by reference, so this post wasn't particularly new or interesting. Unless you're coming from PHP, which is, IMO, a nightmare because everything is passed by value (by default) except objects.
评论 #1364569 未加载
aarongoughabout 15 years ago
I'm actually looking for feedback on this. I know there are quite a few Ruby hackers hanging round HN.<p>Is there something I'm missing here? Some idiom that lets you side-step this problem? I'm questioning it because this problem/solution seems very much at-odds with the elegance and thoroughness of the rest of the language.
评论 #1364350 未加载
mr_justinabout 15 years ago
See Object#clone and Object#dup<p><a href="http://ruby-doc.org/core/classes/Object.html#M000351" rel="nofollow">http://ruby-doc.org/core/classes/Object.html#M000351</a> <a href="http://ruby-doc.org/core/classes/Object.html#M000352" rel="nofollow">http://ruby-doc.org/core/classes/Object.html#M000352</a>
评论 #1364549 未加载
klochnerabout 15 years ago
He referenced not being alone in his assumptions, but this is basic ruby:<p><pre><code> &#62;&#62; a = b = [1,2] =&#62; [1, 2] &#62;&#62; c = a.dup =&#62; [1, 2] &#62;&#62; a==b =&#62; true &#62;&#62; a==c =&#62; true &#62;&#62; a.equal?(b) =&#62; true &#62;&#62; a.equal?(c) =&#62; false </code></pre> Here's a better post on the topic: <a href="http://kentreis.wordpress.com/2007/02/08/identity-and-equality-in-ruby-and-smalltalk/" rel="nofollow">http://kentreis.wordpress.com/2007/02/08/identity-and-equali...</a>
评论 #1364565 未加载
crazydiamondabout 15 years ago
This is not a surprise. I have the same issues with Strings too. A String is passed around your app and someone changes it - capitalizes/chomps etc. The String is changed throughout the app ! You have to dup() it, if you want to ensure no one changes it.<p>This means if you have classes returning Strings, such as first_name, last_name, address etc, your getter should return a dup() if you want to ensure no accidental change to it. That sucks, if you ask me.
评论 #1364594 未加载
jherikoabout 15 years ago
Just to reinforce the other comments - this is pretty much expected behaviour in high level languages.<p>Always read the docs.
aarongoughabout 15 years ago
I actually just had a chat via email with Greg Brown (author of Ruby Best Practices). I updated the blog post to get to the point quicker and I included his take on the matter...
swannodetteabout 15 years ago
As a side note this one of those fundamental language problems that Clojure solves without sacrificing performance.
jcapoteabout 15 years ago
Great read, although I've never been bitten by this particular "bug".
评论 #1364555 未加载