Array operations

Hi all!

What comparison (equality) the array operation ‘-’ based on? I tried to
define ==, ===, even <=>, but none of them gets called. OTOH, if I have
two distinct string objects which happen to contain the same characters,
they are considered equal, even if the ids are not equal.

Thanks:
Ferenc

PS: Merry Christmas to all! :slight_smile:

Hi,

···

In message “array operations” on 03/12/27, Ferenc Engard ferenc@engard.hu writes:

What comparison (equality) the array operation ‘-’ based on? I tried to
define ==, ===, even <=>, but none of them gets called. OTOH, if I have
two distinct string objects which happen to contain the same characters,
they are considered equal, even if the ids are not equal.

Close. It uses “eql?” internally, since comparison is done using
Hash.

						matz.

What comparison (equality) the array operation ‘-’ based on? I tried to
define ==, ===, even <=>, but none of them gets called. OTOH, if I have
two distinct string objects which happen to contain the same characters,
they are considered equal, even if the ids are not equal.

Close. It uses “eql?” internally, since comparison is done using
Hash.

What does hash comparison mean? I have read the Object#hash and
Object#eql? documentation, but they do not mention arrays. Moreover,
there comes the question: what the default Object#hash do? It has a
generic algorithm which computes something based on the object’s
attributes?

Anyway, I have to define both == and eql? in my classes to work
properly? What is the semantical difference of this two method? And then
I have to redefine hash also to ensure that a.eql?(b) implies
a.hash==b.hash?

I try to aim better next time,
Ferenc

Ferenc Engard ferenc@engard.hu writes:

What does hash comparison mean? I have read the Object#hash and
Object#eql? documentation, but they do not mention arrays. Moreover,
there comes the question: what the default Object#hash do? It has a
generic algorithm which computes something based on the object’s
attributes?

Hash comparison means that it compares the value of Object#hash for each
object. This is where a quick look at the Ruby source is very enlightening.
Having had to do some battle with these methods recently myself, I have the
code fresh in my mind. Object#hash just returns the object ID by default.
This is done in C code, so if you override Object#object_id, it will not return
what you expect.

Anyway, I have to define both == and eql? in my classes to work
properly? What is the semantical difference of this two method? And then
I have to redefine hash also to ensure that a.eql?(b) implies
a.hash==b.hash?

You need to define #eql? and #hash for hash comparisons to work properly, and
you need to define #== for the == operator to work. You need to define #=== if
you plan on using these in case statements (although it defaults to using #==),
and #equal? does not need to be redefined.

Hope this helps!

– Samuel

Samuel Tesla wrote:

Ferenc Engard ferenc@engard.hu writes:

What does hash comparison mean? I have read the Object#hash and
Object#eql? documentation, but they do not mention arrays. Moreover,
there comes the question: what the default Object#hash do? It has a
generic algorithm which computes something based on the object’s
attributes?

Hash comparison means that it compares the value of Object#hash for each
object. This is where a quick look at the Ruby source is very enlightening.
Having had to do some battle with these methods recently myself, I have the
code fresh in my mind. Object#hash just returns the object ID by default.
This is done in C code, so if you override Object#object_id, it will not return
what you expect.

Sorry, I didn’t look in the source, yet, but I have made some
experiments with this simple program:

class A
attr_accessor :x

def eql?(o) @x==o.x end

def hash
15
end
end

a=A.new
b=A.new
c=A.new
d=A.new

a.x=1
b.x=2
c.x=2
d.x=3

ar1=[a,b]
ar2=[b]
ar3=[c]
ar4=[d]
ar5=[d,d]
ar6=[b,c]

puts “b.eql?(c)==true”
puts “[a,b]==”+(ar1).inspect
puts “[a,b].uniq==”+(ar1.uniq).inspect
puts “[a,b]-[b]==”+(ar1-ar2).inspect
puts “[a,b]-[c]==”+(ar1-ar3).inspect
puts “[a,b]-[d]==”+(ar1-ar4).inspect
puts “[d,d].uniq==”+(ar5.uniq).inspect
puts “[b,c].uniq==”+(ar6.uniq).inspect

···

The output is:

b.eql?(c)==true
[a,b]==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[a,b].uniq==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[a,b]-[b]==[#<A:0x402d90ac @x=1>]
[a,b]-[c]==[#<A:0x402d90ac @x=1>]
[a,b]-[d]==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[d,d].uniq==[#<A:0x402d8fbc @x=3>]
[b,c].uniq==[#<A:0x402d8fe4 @x=2>]

Which seems correct. Now if I comment out the hash method, the output
changes:

b.eql?(c)==true
[a,b]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b].uniq==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b]-[b]==[#<A:0x402d9174 @x=1>]
[a,b]-[c]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b]-[d]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[d,d].uniq==[#<A:0x402d90ac @x=3>]
[b,c].uniq==[#<A:0x402d90d4 @x=2>, #<A:0x402d90c0 @x=2>]

I.e. b and c are no longer considered equal. Based on that, I have made
the following conclusion:

  1. The array object first gets the hash of the objects it contains
  2. If two object’s hashes are not equal, then it considers as different
    objects
  3. If the hash values are equal, then if first.eql?(second) is true,
    then it considers the objects as equal, otherwise not.

Just like a hash index in a database. So, if I am lazy, can I implement
the #hash method like this, and it will only result in a bigger
comparison executing time because of the more #eql? comparisons, but
will work correctly?

Thanks for the help:
Ferenc