Will Rubinius have fewer dark corners?
Section 3.4.2 of The Ruby Programming Language talks about defining (or overriding) the hash and eql? methods of a class in order to control how objects are treated as keys in a hash… except for strings. Strings are handled specially because they’re “mutable but commonly used as hash keys.”
So when someone asked today on comp.lang.ruby about case-insensitive hash access, the answer, sadly, could not be as simple (and possibly dangerous) as “Just override hash and eql? in String.” Or could it?
Well, I whipped up something quickly:
class String alias old_hash hash def hash self.downcase.old_hash end def eql?(other) self.hash == other.hash end end require 'test/unit' class TestCaseInsensitiveHashAccess < Test::Unit::TestCase def test_case_insensitivity h = {'a' => 1, 'B' => 'buzz'} assert_equal(1, h['A']) assert_equal('buzz', h['b']) end end
I ran it a few times. Ruby failed. Ruby 1.9 failed. JRuby failed. But Rubinius passed.
And why shouldn’t it pass? For every other class, this sort of monkeying with hash and eql? will get you what you want: hash key access mayhem. Why not String?
Well, there might be something sinister hiding in the “mutable but commonly used as hash keys” description. Something subtle. Maybe it’s not subtle and I just haven’t been thinking very clearly. I don’t know.
It looks to me, in the short amount of time I’ve been thinking about this, that Rubinius is more consistently Ruby-ish than Ruby is (at least in this case). Are there more ways in which that’s true?