From: Hugh Sasse Date: 2005-09-14T01:08:47+09:00 Subject: Sets, uniqueness not unique. I have been splitting a comma separated values file, and putting some of the values into an Student class, simply a collection of strings, so that I can build a database table from them: require 'set' class Student attr_accessor :forename, :surname, :birth_dt, :picture, :coll_status def initialize(forename0, surname0, birth_dt0, picture0, coll_status0) @forename = forename0 @surname = surname0 @birth_dt = birth_dt0 @picture = picture0 puts "in student.new() picture is #{picture0.inspect}, @picture is #{@picture.inspect} " if $debug @coll_status = coll_status0 end def eql?(other) # if self.forename == "John" and other.forename == "John" debug = true # end res = [:forename, :surname, :birth_dt, :picture, :coll_status].all? do |msg| print "#{self.send(msg)} == #{(other.send(msg))} gives #{self.send(msg) == (other.send(msg))}" if debug self.send(msg) == (other.send(msg)) end return res end def to_s "#{@surname}, #{@forename}, #{@birth_dt}, #{@picture}, #{@coll_status}" end end And in the body of my program I read the records in from the csv and add the students if they are new. They tend to be clustered in the input, hence the last_student test. class TableMaker INPUT = "hugh.csv" ACCEPTED_MODULES = /^\"TECH(100[1-7]|200\d|201[01]|300\d|301[0-2])/ # Read in the database and populate the tables. def initialize(input=INPUT) @students = Set.new() # [...] open(input, 'r') do |infp| while record = infp.gets record.chomp! puts "record is #{record}" forename, surname, birth_dt, institution_id, aos_code, various, other, fields, picture, coll_status, full_desc = record.split(/\s*\|\s*/) next unless aos_code =~ ACCEPTED_MODULES puts "from record, picture is [#{picture.inspect}]." if $debug # Structures for student student = Student.new(forename, surname, birth_dt, picture, coll_status) if student == last_student student = last_student else student.freeze # Avoid duplicates unless @students.include? student @students.add student end last_student = student end # [...] end end end # [...] end 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. So what's going on? I have checked, and the duplicate students seem to have identical strings, so I wrote the eql? to be sure. I bet this will be a self.kick(self) reason, but I can't see it yet. Thank you, Hugh