2

I can update a hash set to another variable like this:

d = a = {b: 'c'}

a[:b] = 'qwerty'
d # => {:b=>'qwerty'} # What is this magic?

d[:b] = 'blah'
a # => {:b=>'blah'} # And this magic?

Why does this not happen when using primitive variables?

d = a = 'b'

a = 'c'
d # =>'b' # Why is it still the same?
sawa
  • 165,429
  • 45
  • 277
  • 381
teddybear
  • 546
  • 2
  • 6
  • 14
  • 3
    Possible duplicate of [Is Ruby pass by reference or by value?](https://stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value) – jtbandes Nov 05 '17 at 18:28
  • TLDR; An object is itself. Assigning (or otherwise using) an object in Ruby does not create a copy/clone/duplicate of said object. – user2864740 Nov 05 '17 at 18:38
  • 1
    Not an exact duplicate, according to @mu is too short. I agree. – Wayne Conrad Nov 05 '17 at 20:16
  • 1
    There is no such thing as a "primitive" in Ruby. The two code snippets don't have different results because of some vague notion of "primitiveness", they have different results because they do completely different things. – Jörg W Mittag Nov 05 '17 at 21:51
  • _"Why does updating a hash [...] update that variable?"_ – it doesn't. Updating a hash just updates the hash. No variable is being changed. In your first example both, `a` and `d` refer to the same object all the time. You can use `a` and `d` interchangeably. – Stefan Nov 07 '17 at 08:39

2 Answers2

5

You're doing two very different things.

Your "primitive variable" example:

a = 'b'
d = a
a = 'c'

is a simple assignment so that at the end of line 2, a and d refer to the same object. Then on line 3, a is assigned a new object and a and d end up referring to different objects.

Your first example:

a = {b: 'c'}
d = a
a[:b] = 'qwerty'

is an assignment followed by a call to a method that mutates its receiver. The third line could also be written as one of the following that make the the method call more explicit:

a.[]=(:b, 'qwerty')
a.send(:[]=, :b, 'qwerty')

So you're comparing an assignment by a mutating method call with a series of assignments.

If your second example used a mutator method on a:

a = 'b'
# => 'b'
d = a
# => 'b'
a[0] = 'c' # String#[]= alters its receiver
# => 'c'
d
# => 'c'

then both a and d would change because you're not doing an assignment to change the object that a refers to, you're changing the referred object.


This question isn't quite a duplicate of Is Ruby pass by reference or by value?, close but not quite. I'm sure this is a duplicate of several other questions but I can't find them right now. If someone finds a proper duplicate, let me know and I'll delete this and pull out my dupe-hammer.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
1

Unlike for primitives both variables point to the same underlying object. If you need a copy you can use clone or dup.

s1mpl3
  • 1,456
  • 1
  • 10
  • 14