Tim Sutherland wrote:

…

I just realised why

It’s because we require that a.eql?(b) implies a.hash == b.hash.

Forcing people who define #== to be structural equality to also define #hash

to follow this would be an onerous restriction.Similarly, defining Set#hash that behaves nicely if eql? is == is tricky

because we don’t have a nice ordering of elements in the set. Need something

like SortedSet but with sort_by to use ==. (Since element#<=> does not have

to match element#==.)

You don’t need an ordering to define a nice Set#eql?

(resp. Set#hash) method. Essentially something like

class Set

def eql?(rhs)

rhsh = @rhs.hash

return false unless @hash.size == rhsh.size

@hash.each_key {|e| return false unless rhs.has_key?(e)}

return true

end

```
def hash
# some silly order independent hash ...
hsh = @hash.size + 1743
_hsh = hsh*hsh
@hash.each_key {|e|
ehsh = e.hash
hsh += ehsh
_hsh ^= (ehsh >> 13)
}
return (hsh && _hsh) + hsh
end
```

end

would do. The Set class author was certainly aware of this

possibility but (probably) decided against it since he modeled

his Set class more closely around Ruby’s Hash class than

classical mathematical sets. The current Set#<=> implementation

is IMO even more debatable since it is based on the sets size

rather than their actual members (this is akin to the dubious

Complex#<=> definition which which still ticks me off after > 3

years).

/Christoph