0

I'm in the process of building my own webserver and want to make a logger. After server get a message, I want both to log it and send the message to the parsers. I need to make some moditications to the message for logging (eg remove the password), but when I change second variable, first is changed too!

msg = log_msg = JSON.parse(something)

log_msg[:password] = '[FILTERED]'

raise msg.inspect # => {..., :password => '[FILTERED]'}

How can I avoid this behavior of my code?

UPDATED It seems more strange, because of irb:

2.2.1 :001 > a = b = 1
 => 1 
2.2.1 :002 > b = 2
 => 2 
2.2.1 :003 > b
 => 2 
2.2.1 :004 > a
 => 1
Alex Antonov
  • 14,134
  • 7
  • 65
  • 142

2 Answers2

2

After the assignment, msg and log_msg reference to the same object. If this is not what you expected, try this:

log_msg = JSON.parse(something)
msg = log_msg.dup

Note that the other example behave differently because Fixnum is special. From the manual:

Fixnum objects have immediate value. This means that when they are assigned or passed as parameters, the actual object is passed, rather than a reference to that object.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Why does `irb` has expected behavior? Please review my update to question – Alex Antonov Jun 09 '15 at 08:19
  • 1
    irb "works" as intended because you are using immutable values in your example. Arrays and Integers will not have the same behaviour (you cannot change the value of an Integer, you just point to another instance when changing the value of a variable) – floum Jun 09 '15 at 08:21
  • Thanks a lot, Yu Hao! – Alex Antonov Jun 09 '15 at 08:22
  • @floum as of arrays, you are wrong. arrays are mutable, so assigning an array to two variables and changing one of them would affect the second aswell. – twonegatives Jun 09 '15 at 08:29
  • You are definitely right, my comment was not clear enough : Integers are immutable while Arrays are mutable (I was talking about the second example, which is using Integers) – floum Jun 09 '15 at 09:16
1

This question is tightly linked to the following duscussions:

  1. Object assignment in ruby
  2. Does ruby pass by reference or by value
  3. Ruby parameters by reference or by value

Please read them carefully to understand what's going on (this addressed your code snippet with assigning integer values aswell).

To assign by value you could clone or dup methods. Check the value of object_id to realize if you're working on the same object or not.

a = {}      # => {} 
b = a       # => {} 
b.object_id # => 114493940 
a.object_id # => 114493940 
b = a.clone # => {} 
b.object_id # => 115158164
a.object_id # => 114493940 
Community
  • 1
  • 1
twonegatives
  • 3,400
  • 19
  • 30