Why am I getting - "`force_encoding': can't modify frozen String (RuntimeError)"

# encoding: ascii-8bit

arr = {
      '1p' => 1,
      '2p' => 2,
      '5p' => 5,
      '10p' => 10,
      '20p' => 20,
      '50p' => 50,
      '£1' => 100,
      '£2' => 200
    }

arr.keys
# => ["1p", "2p", "5p", "10p", "20p", "50p", "\xC2\xA31", "\xC2\xA32"]
arr.keys.map{|e| e + ' test'}
# => ["1p test",
# "2p test",
# "5p test",
# "10p test",
# "20p test",
# "50p test",
# "\xC2\xA31 test",
# "\xC2\xA32 test"]

Q. while the above code does work,why not the below?

arr.keys.map{|e| e.force_encoding('utf-8')} # =>
# ~> -:14:in `force_encoding': can't modify frozen String (RuntimeError)
# ~> from -:14:in `block in <main>'
# ~> from -:14:in `map'
# ~> from -:14:in `<main>'

···

--
Posted via http://www.ruby-forum.com/.

Excerpts from Love U Ruby's message of 2013-11-24 17:26:40 +0100:

# encoding: ascii-8bit

arr = {
      '1p' => 1,
      '2p' => 2,
      '5p' => 5,
      '10p' => 10,
      '20p' => 20,
      '50p' => 50,
      '£1' => 100,
      '£2' => 200
    }

arr.keys
# => ["1p", "2p", "5p", "10p", "20p", "50p", "\xC2\xA31", "\xC2\xA32"]
arr.keys.map{|e| e + ' test'}
# => ["1p test",
# "2p test",
# "5p test",
# "10p test",
# "20p test",
# "50p test",
# "\xC2\xA31 test",
# "\xC2\xA32 test"]

Q. while the above code does work,why not the below?

arr.keys.map{|e| e.force_encoding('utf-8')} # =>
# ~> -:14:in `force_encoding': can't modify frozen String (RuntimeError)
# ~> from -:14:in `block in <main>'
# ~> from -:14:in `map'
# ~> from -:14:in `<main>'

Since Strings are so commonly used as keys and that having mutable
objects as hash keys requires caution, when Hash#= is given a string
key it duplicates it, freezes the copy and uses the copy as key. When
you call force_encoding on the key, it fails because it can't modify a
frozen string. On the other hand, e + ' test' doesn't modify the string
e; rather it creates a new (not frozen) string which is composed by the
content of e and the content of ' test'.

I hope this helps

Stefano

Stefano Crocco wrote in post #1128478:

Excerpts from Love U Ruby's message of 2013-11-24 17:26:40 +0100:

      '£2' => 200
# "50p test",

Since Strings are so commonly used as keys and that having mutable
objects as hash keys requires caution, when Hash#= is given a string
key it duplicates it, freezes the copy and uses the copy as key. When
you call force_encoding on the key, it fails because it can't modify a
frozen string. On the other hand, e + ' test' doesn't modify the string
e; rather it creates a new (not frozen) string which is composed by the
content of e and the content of ' test'.

Thanks for your point!! Yes I confirmed the same as below :

hsh = {
      '1p' => 1,
      '2p' => 2,
      '5p' => 5,
      '10p' => 10,
      '20p' => 20,
      '50p' => 50,
      '£1' => 100,
      '£2' => 200
    }

hsh.key(1).object_id # => 70011540
hsh.keys.each_with_object({}){|e,h| h[e]=e.object_id}['1p']
# => 70011540

Actually Class: Hash (Ruby 2.0.0) says
gives us a new array, which I misunderstood something wrong way..

Again thank you very much.

···

--
Posted via http://www.ruby-forum.com/\.