(I sent this to ruby-doc by accident, and got a response, but I am
reposting to ruby-talk, sorry for the cross-post.)
Thanks, thats very informative, and I would not have guessed.
I tried a different approach, I derived from String. This has the
very odd behaviour of blowing the Stack!
class Str < String
def hash; self.downcase.hash; end # <- this doesn't look recursive
# to me, but it blows the stack
end
h = { }
k = Str.new('a')
k == 'A'
'A' == k
h[k] = 'lower'
k = Str.new('A')
p k.downcase # Should return an instance of String, right?
p k.downcase.hash # <--- this line cause stack overflow
k.hash == 'a'.hash
h.has_key? k
I think Str#downcase should return the same thing as String#downcase =>
a String, and not a Str, so I don't see why there is a recursive call,
here.
What am I missing?
Thanks,
Sam
Quoting g_ogata@optushome.com.au, on Mon, Mar 14, 2005 at 05:41:40AM +1100:
···
Sam Roberts <sroberts@uniserve.com> writes:
> I've tried:
>
>
> h = { }
>
> k = 'a'
>
> class << k
> def hash; self.downcase.hash; end
> def ==(s); self.downcase == s.downcase; end
> def eql?(s); self == s; end
> def ===(s); self == s; end
> end
>
> k = 'A'
>
> class << k
> def hash; self.downcase.hash; end
> def ==(s); self.downcase == s.downcase; end
> def eql?(s); self == s; end
> def ===(s); self == s; end
> end
>
> k == 'a'
> k.hash == 'a'.hash
>
> # I want this to be true!
> h.has_key? k
>
> But it doesn't work. I'm particularly confused because if I write a
> class Str that wraps String and defines those methods things do work
> out...
>
> Any pointers?This looks like a consequence of the fact that when ruby takes the
hash of a key, if the key is a String, it uses the default
implementation of String#hash directly, even if String#hash has been
redefined, or the object has a singleton class. (The same thing is
true with Fixnums and Symbols.)Try:
class String
def hash
puts '!'
super
end
end
{}['a'] = 1Then change the String to an Object.
HTH.