That is very interesting.
The two strings are identical (aside from one being frozen):
require "objspace"
hash = {}
key = "ABC OÜ"
p key.hash
key.slice!(/ oü$/i)
p key.hash
puts ObjectSpace.dump(key)
hash[key] = true
p "#{key} in #{hash}: value is #{hash[key].inspect}"
puts ObjectSpace.dump(hash.keys.first)
p [hash.keys.first, key, hash.keys.first == key]
p [hash.keys.first.hash, key.hash]
1883393806954673666
-2878200511277543492
{"address":"0x10129f048", "type":"STRING", "class":"0x1011c2418", "embedded":true, "bytesize":3, "encoding":"UTF-8", "memsize":40, "flags":{"wb_protected":true}}
"ABC in {\"ABC\"=>true}: value is nil"
{"address":"0x10129ebc0", "type":"STRING", "class":"0x1011c2418", "frozen":true, "embedded":true, "fstring":true, "bytesize":3, "value":"ABC", "encoding":"UTF-8", "memsize":40, "flags":{"wb_protected":true}}
["ABC", "ABC", true]
[-2878200511277543491, -2878200511277543491]
The hash code is the same, and ==
returns true.
I had a quick look at recent changes in String#slice!
that could explain why it's fixed in 3.2, but didn't spot anything yet.
What is interesting though is that the first access to key.hash
returns -2878200511277543492
, but then later it consistently returns -2878200511277543491
. I wonder if there is an off by one bug somewhere.