2

I am not sure how this variable called origString is changing value in my loop

def scramble_string(string, positions)
  i = 0
  origString = string
  puts origString
  newString = string
  while i < string.length
    newString[i] = origString[positions[i]]
    i = i + 1
  end
  puts origString
  return newString
end

for example if I run scramble_string("abcd", [3, 1, 2, 0]) origString changes from "abcd" in the first "puts" to "dbcd" in the second one. How am I changing the value of origString if I am only declaring it once?

5
  • 1
    Ruby strongly recommends using names like orig_string, no upper-case letters, as case has significant meaning in Ruby. Commented Sep 3, 2017 at 23:56
  • The variable isn't changing its value. The value is changing its content, because you tell it to on line 7. Commented Sep 4, 2017 at 13:11
  • @JörgWMittag can you elaborate? how it works " value is changing its content". Commented Sep 5, 2017 at 10:11
  • @Dharshan: If an object supports changing its state, you can change its state by sending it a message telling it to change its state. For example, you can change the state of a string by sending it the []= message or the upcase! message. Commented Sep 5, 2017 at 10:38
  • @JörgWMittag based on tadman's answer when we say x = y both object_ids are same, If we change entire value of x = 'pest', object_ids will change completely. If we check before changing value object_ids of x[0] and y[0] are different. . But changing a single value in x (i,e x[0]) reflects in original string y, HOW? Commented Sep 5, 2017 at 11:05

1 Answer 1

5

When you say x = y in Ruby that creates a variable with a reference to exactly the same object. Any modifications to x will apply to y and vice-versa:

y = "test"
x = y

x[0] = "b"

x
# => "best"
y
# => "best"

You can tell because of this:

x.object_id == y.object_id
# => true

They're identical objects. What you want is to make a copy first:

x = y.dup
x[0] = "b"
x
# => "best"
y
# => "test"

This results in two independent objects:

x.object_id == y.object_id
# => false

So in your case what you need is to change it like:

orig_string = string.dup

Now that being said, often the best way to process things in Ruby is by using functions that return copies, not manipulating things in place. A better solution is this:

def scramble_string(string, positions)
  (0...string.length).map do |p|
    string[positions[p]]
  end.join
end

scramble_string("abcd", [3, 1, 2, 0])
"dbca"

Note that's a lot more succinct than the version with string manipulation.

Sign up to request clarification or add additional context in comments.

3 Comments

Or string.chars.values_at(*positions).join
@tadman need some explanation on your statements. when we say x = y both object_ids are same, but object_ids of x[0] and y[0] are different. If we change entire value of x = 'pest' object_id will completely change. But changing a single value in x reflects in original string y, HOW? Need to know little bit more about this.
x[0] returns a single-character substring. Since every substring operation can produce new, unique string, even x[0].object_id == x[0].object_id is generally not true. There's only a few things that are object_id equivalent by design: Symbols, nil, true, false, and some numbers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.