Set and Object equivilence

Hi,

I've just started with Ruby from Java, and am having trouble getting a
set to recognise equivalence between objects. Basically it is adding
multiple equal objects to the set.

I have created a class and overridden all of the operators <=> , ==,
<, >, eqls?, equals?, hash to indicate that it should use an internal
variable to compare.

Please find enclosed a unit test, the object, and the output from the
test. Cool language BTW. Really enjoying it up until this moment. I'm
probably missing some subtlety of the language.

Any help greatly appreciated.
-------- source starts --------

require "test/unit"
require "set"

class JunkTest < Test::Unit::TestCase
    def test_arraysMuckingAroundWith
        a = Thingy.new(1)
        b = Thingy.new(2)
        c = Thingy.new(1)
        d=Set.new
        d << a
        d << b
        d << c
        puts "output set, with duplicates - the first 2 object should
be equivilent" + d.sort.to_s
    end
end

class Thingy

    attr_accessor :value

    def <=> (thing)
        self.value <=> thing.value
    end

    def == (thing)
        self.value == thing.value
    end

    def > (thing)
        self.value > thing.value
    end

    def < (thing)
        self.value < thing.value
    end

    def eqls? (thing)
        self.value.eqls?(thing.value)
    end

    def equals? (thing)
        self.value.equals?(thing.value)
    end

    def initialize(val)
        @value = val
    end

    def hash
        puts "hash " + @value.hash.to_s
        @value.hash
    end

    def to_s
        value.to_s + ", "
    end
end
-------- source ends --------

-------- output starts --------

C:\dev\ruby\bin\ruby.exe -e
"STDOUT.sync=true;STDERR.sync=true;load($0=ARGV.shift)" C:/projects/
SearchJars/test/JunkTest.rb --name test_arraysMuckingAroundWith
Loaded suite C:/projects/SearchJars/test/JunkTest
Started
hash 3
hash 5
hash 3
output set, with duplicates - 1, 1, 2,
.
Finished in 0.0 seconds.

1 tests, 0 assertions, 0 failures, 0 errors

Process finished with exit code 0

-------- output ends --------

Regards

Andrew Oxenburgh

    def eqls? (thing)
        self.value.eqls?(thing.value)
    end

You've got the name wrong, it should be eql?(thing).

    def equals? (thing)
        self.value.equals?(thing.value)
    end

You probably mean equal?(thing), but you should never redefine
equal?(x) anyway as it always assumed to be an object identity
test.

Gary Wright

···

On Dec 11, 2007, at 10:07 AM, andrew.oxenburgh@gmail.com wrote:

Hi,

I've just started with Ruby from Java, and am having trouble getting a
set to recognise equivalence between objects. Basically it is adding
multiple equal objects to the set.

I have created a class and overridden all of the operators <=> , ==,
<, >, eqls?, equals?, hash to indicate that it should use an internal
variable to compare.

Please find enclosed a unit test, the object, and the output from the
test. Cool language BTW. Really enjoying it up until this moment. I'm
probably missing some subtlety of the language.

Any help greatly appreciated.
-------- source starts --------

require "test/unit"
require "set"

class JunkTest < Test::Unit::TestCase
    def test_arraysMuckingAroundWith
        a = Thingy.new(1)
        b = Thingy.new(2)
        c = Thingy.new(1)
        d=Set.new
        d << a
        d << b
        d << c
        puts "output set, with duplicates - the first 2 object should
be equivilent" + d.sort.to_s
    end
end

class Thingy

    attr_accessor :value

    def <=> (thing)
        self.value <=> thing.value
    end

    def == (thing)
        self.value == thing.value
    end

    def > (thing)
        self.value > thing.value
    end

    def < (thing)
        self.value < thing.value
    end

    def eqls? (thing)

Spelling error: this method needs to read "eql?". This is likely the
cause for your issue.

        self.value.eqls?(thing.value)
    end

    def equals? (thing)
        self.value.equals?(thing.value)
    end

    def initialize(val)
        @value = val
    end

    def hash
        puts "hash " + @value.hash.to_s
        @value.hash
    end

    def to_s
        value.to_s + ", "
    end
end
-------- source ends --------

-------- output starts --------

C:\dev\ruby\bin\ruby.exe -e
"STDOUT.sync=true;STDERR.sync=true;load($0=ARGV.shift)" C:/projects/
SearchJars/test/JunkTest.rb --name test_arraysMuckingAroundWith
Loaded suite C:/projects/SearchJars/test/JunkTest
Started
hash 3
hash 5
hash 3
output set, with duplicates - 1, 1, 2,
.
Finished in 0.0 seconds.

1 tests, 0 assertions, 0 failures, 0 errors

Process finished with exit code 0

-------- output ends --------

It seems the output does not stem from the code you present because
the print statement looks different.

Few remarks: you can make your life easier by including Comparable and
only implementing <=>; then <, <=, > and >= will be automatically be
derived.

You can make your life even simpler by just doing

Thing = Struct.new :value

Cheers

robert

···

2007/12/11, andrew.oxenburgh@gmail.com <andrew.oxenburgh@gmail.com>:

--
use.inject do |as, often| as.you_can - without end

Hi Andrew,

First, change your .eqls? method to .eql? and that will fix your code.

Also, you should look into the Comparable mix-in module. Basically,
if you define the spaceship operator (<=>) and include Comparable in
your class, it will define it will define all the relational operators
(==, <, <=, >, >=) and between? for you. Plus, != is internally
implemented as the boolean negation of ==, so you get that also.

For Set member equality, two methods are used -- eql? and hash.

Eric

···

====

On-site, hands-on Ruby training is available from http://LearnRuby.com
!

Thanks. Bit embarrassed with a simple spelling error. I looked at it
for ages, and tried all sorts of permutations and combinations of set
c'strs and adding methods!

I'll check out the Comparable mixin as well.

Regards

···

On Dec 11, 3:30 pm, "Eric I." <rubytrain...@gmail.com> wrote:

Hi Andrew,

First, change your .eqls? method to .eql? and that will fix your code.

Also, you should look into the Comparable mix-in module. Basically,
if you define the spaceship operator (<=>) and include Comparable in
your class, it will define it will define all the relational operators
(==, <, <=, >, >=) and between? for you. Plus, != is internally
implemented as the boolean negation of ==, so you get that also.

For Set member equality, two methods are used -- eql? and hash.

Eric

====

On-site, hands-on Ruby training is available fromhttp://LearnRuby.com
!