(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'] = 1
> 
> Then change the String to an Object.
> 
> HTH.
> 
>