tags:

views:

35

answers:

1

Hi,

This is a quick question. I have the following ruby code, which works fine.

  def add_zeros number, zeros
    number = number.to_s
    zeros_to_add = zeros - number.length
    zeros_to_add.times do
      number = "0#{number}"
    end
    number
  end

But if I replace

number = "0#{number}"

With

number.insert(0, "0")

Then I get TypeError: can't modify frozen string, does anyone know why this is?

+1  A: 

If the passed argument number is already a frozen string to start with, then number = number.to_s won't change a thing and you won't be able to modify it in place (with number.insert):

add_zeros("24".freeze, 10)  # => TypeError: can't modify frozen string

Creating a new string from it ("0#{number}") is not a problem, of course.

The reason why your string is frozen is subtle. When you use a string as a hash key, Ruby will make a copy of it and freeze it:

s = "hello"
h = {}
h[s] = :world
key = h.keys.first  
key.equal?(s)  # => false  (Ruby made a copy)
key.frozen?    # => true   (Ruby automatically freezes the copy)

Anyways, as a general rule, a method should not modify its arguments.

In this case, you probably want to use rjust:

24.to_s.rjust(10, "0") # => "0000000024"
Marc-André Lafortune
Thanks for your answer,I wasn't aware that the string I was passing it was a frozen string (but now I think of it, are strings passed in as an argument are automatically considered `frozen`??). I think I may need to learn more about this!! I wanted to add the number.to_s for the cases when an integer was passed although sometimes it might be a string.But I will look at more info on frozen strings, thanks so much for the advice it is appreciated.Thanks also for the tip on rjust, that is very helpful, I will be using this instead!
Richard
Ah, right, I forgot to say why your string was frozen in the first place. Check my updated answer.
Marc-André Lafortune