Hash freezes String keys are returns copy

Hi,

My observation is, that Hash behaves differently for different kinds of objects. While an Object key is preserved as is, a String key isn't (it's frozen and a copy is returned)! I'd like to get back my original key from a Hash, but with String keys this is not possible.

   a = 'test'
   b = Object.new

   h = {}
   h[a] = a
   h[b] = b

   h.each do |k,v|
     puts "key: "
     p k
     p k.object_id
     p k.frozen?

     puts "value: "
     p v
     p v.object_id
     p v.frozen?
   end

The result is (indented for readability):

key:
   #<Object:0x81f239c>
   68129230
   false
value:
   #<Object:0x81f239c>
   68129230
   false

key:
   "test"
   68135310
   true
value:
   "test"
   68135320
   false

Is this intended behaviour?

So in my case, instead of { obj => data }, I now have to store
{ obj => [obj, data] }, as I can't get the original object "obj" back.

Regards,

   Michael

Is this intended behaviour?

What do you do in this case ?

  a = "test"
  hash[a] = "test"
  a[0] = "m"
  p hash.keys

Guy Decoux

ts wrote:

"M" == Michael Neumann <mneumann@ntecs.de> writes:

> Is this intended behaviour?

What do you do in this case ?

  a = "test"
  hash[a] = "test"
  a[0] = "m"
  p hash.keys

But why does this work:

   a =
   hash[a] = "test"
   a[0] = "1"
   p hash.keys
   # => returns [ ["1"] ]

Regards,

   Michael

But why does this work:

   a =
   hash[a] = "test"
   a[0] = "1"
   p hash.keys
   # => returns [ ["1"] ]

uln% cat b.rb
#!/usr/local/bin/ruby
a =
hash = { a => "test"}
a[0] = "1"
p hash[a]
uln%

uln% b.rb
nil
uln%

Guy Decoux

ts wrote:

"M" == Michael Neumann <mneumann@ntecs.de> writes:

> But why does this work:

> a =
> hash[a] = "test"
> a[0] = "1"
> p hash.keys
> # => returns [ ["1"] ]

uln% cat b.rb
#!/usr/local/bin/ruby
a =
hash = { a => "test"}
a[0] = "1"
p hash[a]
uln%

uln% b.rb
nil
uln%

okay... but isn't it the same when using a String?

   a = ""
   hash = { a => "test" }
   a << "1"
   p hash[a] # => nil
   p hash.keys # => [""]

while:

   a =
   hash = { a => "test" }
   a << "1"
   p hash[a] # => nil
   p hash.keys # => [["1"]]

they behave differently.

Regards,

   Michael

okay... but isn't it the same when using a String?

this is made volontary for efficienty : otherwise each time that you
modify an object, used as a key, ruby will need to re-hash the hash if you
don't want to have strange result like the example that I've given

In reality when you write

   a = "test"
   hash[a] = "test"

the key and `a' share the same string, but `a' is marked copy-on-write

they behave differently.

Search the archive of [ruby-talk] for this :slight_smile:

Guy Decoux

ts wrote:

"M" == Michael Neumann <mneumann@ntecs.de> writes:

> okay... but isn't it the same when using a String?

this is made volontary for efficienty : otherwise each time that you
modify an object, used as a key, ruby will need to re-hash the hash if you
don't want to have strange result like the example that I've given

In reality when you write

   a = "test"
   hash[a] = "test"

the key and `a' share the same string, but `a' is marked copy-on-write

> they behave differently.

Search the archive of [ruby-talk] for this :slight_smile:

Ah, IIRC it has something to do with common usage of strings as keys.

Regards,

   Michael

"Michael Neumann" <mneumann@ntecs.de> schrieb im Newsbeitrag news:41BDDE56.3030305@ntecs.de...

ts wrote:

"M" == Michael Neumann <mneumann@ntecs.de> writes:

> okay... but isn't it the same when using a String?

this is made volontary for efficienty : otherwise each time that you
modify an object, used as a key, ruby will need to re-hash the hash if you
don't want to have strange result like the example that I've given

In reality when you write

   a = "test"
   hash[a] = "test"

the key and `a' share the same string, but `a' is marked copy-on-write

> they behave differently.

Search the archive of [ruby-talk] for this :slight_smile:

Ah, IIRC it has something to do with common usage of strings as keys.

Yes, it's a special optimization for string keys. You can get your original out if you freeze it before putting it into the hash. :slight_smile: In fact, that might be a performance optimization if you put *a lot* string keys into the hash.

Because copying an instance is relatively expensive this pattern was not adopted generally, i.e. you have to take care of Array and other keys yourself. Note also, that you need to rehash if you change your array instance after using it as Hash key.

Kind regards

    robert