conor
conor

Reputation: 123

Unexpected behavior when changing a character in a string in Ruby

This code (in Ruby 1.9)

word = 'atf'
new_word = word
word[0] = 'w'
puts new_word 

gives the response "wtf", this

word = 'ok'
new_word = word
word = 'wft'
puts new_word

gives the response "ok" which is much more what I'd expect. Is this a bug in Ruby or am I wrong in my expectation that changing word, however I change it, shouldn't change new_word.

Upvotes: 1

Views: 93

Answers (4)

reto
reto

Reputation: 16732

As said in the other answers you are pointing to variables to the same string object.

''Please remmber'': Ruby never copies/duplicates an object just by assigning it (or returning, or passing to a function). So if you are coming from C/C++, Ruby only works with references/pointers. (And if you are coming from Java: the behavior is very similar to Java non-primitives).

for example:

a = [1, 2]
b = a
b << 3
puts a.inspect
# prints [1, 2, 3]

or even more confusing if you are not used to it:

def foo(x)
  x << 3 
  return nil
end

a = [1, 2]
foo(a)
foo(a)
puts a.inspect
# prints [1, 2, 3, 3]

In some cases Ruby provides two methods of the same functionality, one which changes the actual object, the other returns a new object containing the changes.

For example String#gsub(from, to) returns a new String containing these changes, on the other hand String#gsub!(from, to)changes the string itself. Another example would beArray#rejectvs.Array#reject!`

Object#dup copies an object (but not its nesting objects).

Please note: in most cases not modifying a String is considered good style

Upvotes: 1

Roland Mai
Roland Mai

Reputation: 31077

The important thing to note is the meaning of:

new_word = word

The assignment does not copy the value of word into new_word. It sets makes the variable new_word point to the same memory address as the variable word.

Therefore, new_word[0] = 'x' and word[0] = 'x' will have the same effect on the value of both variables new_word and word.

You can fix the problem by doing either:

new_word = word.dup 

or

new_word = word.clone

clone and dup create copies in memory of the value of the variable, and return a reference to that memory, which is then assigned to new_word. There are differences between clone and dup but they're beyond the scope of your question.

Additionally, you will find that many languages function in this way. For instance, you can try the same semantics in C# or javascript, and see the same behavior.

Upvotes: 0

Mladen Jablanović
Mladen Jablanović

Reputation: 44080

word[0] = 'w' is a method call on an object referenced by word variable.

word = 'wft' is variable assignment.

Upvotes: 1

David Grayson
David Grayson

Reputation: 87386

In the first example, there is only one actual string object, and you have two variable names that refer to it. Modifying the string therefore modifies each variable. You could instead do:

new_word = word.dup

to make a copy.

Upvotes: 3

Related Questions