Set and Object equivilence

A

andrew.oxenburgh

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
 
G

Gary Wright

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
 
R

Robert Klemme

2007/12/11 said:
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
 
E

Eric I.

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
!
 
A

andrew.oxenburgh

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top