On Wed, 14 Sep 2005, David A. Black wrote: > Hi -- > > On Wed, 14 Sep 2005, Hugh Sasse wrote: > >> This being a Set I don't really need the call to include? now, but >> it's there (from when I was using a hash for this). >> >> I find two things that seem odd to me: >> >> 1. eql? is never getting called, despite include?. >> >> 2. I end up with duplicate students. >> >> Sets *can't* hold duplicates, and include depends on eql? for Sets. > > Are you sure about that latter point? In set.rb: > > def include?(o) > @hash.include?(o) > end > > and in hash.c: > > if (st_lookup(RHASH(hash)->tbl, key, 0)) { > return Qtrue; > ... } > > I haven't followed the trail beyond that... but I think any two > student objects will count as different hash keys, even if they have > similar string data. > > > David Right, there is some definite wierdness going on here. I removed the definition of eql? and set the hash to use MD5 sums. I still didn't get unique entries in my set. Now I have require 'md5' class Student # [...] FIELDS = [:forename, :surname, :birth_dt, :picture, :coll_status] def initialize(forename0, surname0, birth_dt0, picture0, coll_status0) # [...] @hash = FIELDS.inject(MD5.new()) do |d,m| d << send(m) end.hexdigest.hex end def hash @hash end def eql?(other) self.hash == other.hash end end And this works. Remmove the definition of eql? and include? always gives untrue (I've not checked to see if it is nil or false). This is in accordance with the entry in Pickaxe2 (page 570, Object#hash) and ri, that: ------------------------------------------------------------ Object#hash obj.hash => fixnum ------------------------------------------------------------------------ Generates a +Fixnum+ hash value for this object. This function must have the property that +a.eql?(b)+ implies +a.hash == b.hash+. The hash value is used by class +Hash+. Any hash value that exceeds the capacity of a +Fixnum+ will be truncated before being used. (I'm not sure if my digests are too big) What i don't really know is what the sufficient conditions are for this? Is it *necessary* to change hash and eql together? What are the defaults for Set? I suspect that my eql? ought to be def eql?(other) FIELDS.inject(true) do |b,v| t && (self.send(m) == other.send(m)) end end for that matter Hugh