0

Please someone tell me how it works? Setting of hash key with the same name with instance variable @remote take affect on its own value... How?

@remote = { url: '/user/validate', type: :post }
@config = {}
@config[:remote] = {}

def test
  @config[:remote] = @remote

  data = { data: 'some data' }
  @config[:remote][:data] = data
end

# call method test
test

p @remote.to_s # => "{:url=>\"/user/validate\", :type=>:post, :data=>{:data=>\"some data\"}}"
p @config.to_s # => "{:remote=>{:url=>\"/user/validate\", :type=>:post, :data=>{:data=>\"some data\"}}}"
  • You're wondering why `@remote` gets a `:data` key when you say `@config[:remote][:data] = data`? – mu is too short Feb 16 '18 at 22:31
  • @mu-is-too-short yes, exactly ... – Sergey Shirnin Feb 16 '18 at 22:37
  • `@config[:remote] = @remote` doesn't copy `@remote`, it just assigns a reference. Look at `@config[:remote].object_id` and `@remote.object_id`. All values in Ruby are references (but not all of them are mutable so implementations can take short cuts with things like `11` and `true`) so assignment just copies the reference not what it refers to. There are probably hundreds of duplicates of this, it is a very common point of confusion. – mu is too short Feb 16 '18 at 22:43

1 Answers1

1

Ruby is one of many languages that distinguish "immediate values" and "reference values".

If I say x = 5; y = x; y = 6, then x is an immediate value, and still contains 5, not 6.

But if I say x = { value: 5 }, then x is a reference to a hash object. When I say y = x then y refers to the same hash object as x does. So y[:value] = 6 will make x[:value] == 6.

To prevent this behavior, look up "ruby deep copy", and use y = x.dup.

Phlip
  • 5,253
  • 5
  • 32
  • 48
  • See also https://stackoverflow.com/questions/22827566/ruby-parameters-by-reference-or-by-value – Frederik Spang Feb 16 '18 at 22:51
  • But if you `x = 5; y = x` then both `x` and `y` refer to the same object, the `y = 6` part is a bit misleading. The difference between the two examples is that `5` is immutable but a hash is not. AFAIK the immediacy of immutable objects like `11`, `:symbol`, ... is an implementation detail in MRI rather than a property of Ruby itself. And `#dup` doesn't do a deep copy as `h1 = { k: [11] }; h2 = h1.dup; h2[:k].push(23)` will show. – mu is too short Feb 16 '18 at 23:00