Customizing Array#uniq by defining eql?

59 views
Skip to first unread message

Marcel Molina Jr.

unread,
Mar 7, 2005, 3:16:17 PM3/7/05
to
PickAxe II's documentation for Array#uniq says,

Returns a new array by removing duplicate values in _arr_, where
duplicates are detected by comparing using +eql?+.

Given that say I have a simple class:

class PossibleTime
attr_reader :day, :start_time, :end_time

def initialize(day, start_time, end_time)
@day, @start_time, @end_time = day, start_time, end_time
end

def hash
"#@day #@start_time #@end_time"
end

def ==(other_pt)
self.hash == other_pt.hash
end

def eql?(other_pt)
self == other_pt
end
end

Here +eql?+ is defined in terms of +==+. Creating two example instances shows
these methods working:

> a = PossibleTime.new('M', '9:30', '10:30')
> b = PossibleTime.new('M', '9:30', '10:30')
> c = PossibleTime.new('T', '9:30', '12:00')
> a == b
=> true
> a.eql? b
=> true
> a == c
=> false
> [a,b].uniq.size
=> 2
> # I was expecting 1, not 2

I'll add debugging to see if +eql?+ was even called:

class PossibleTime
def eql?(other_pt)
puts 'eql? called'
self == other_pt
end
end

> a.eql? b
eql? called
=> true
> a.eql? c
eql? called
=> false
> [a,b].uniq.size
=> 2

So eql? isn't even being called.

Am I overlooking something? Specifying something incorrectly? Not
understanding the fundamental interaction between eql? and uniq?

Thanks for your time,
marcel
--
Marcel Molina Jr. <mar...@vernix.org>


Yukihiro Matsumoto

unread,
Mar 7, 2005, 8:21:00 PM3/7/05
to
Hi,

In message "Re: Customizing Array#uniq by defining eql?"


on Tue, 8 Mar 2005 05:16:17 +0900, "Marcel Molina Jr." <mar...@vernix.org> writes:

|PickAxe II's documentation for Array#uniq says,
|
| Returns a new array by removing duplicate values in _arr_, where
| duplicates are detected by comparing using +eql?+.

It creates hash internally to remove redundant values, so that
comparison is done by "eql?" but it is filtered by "hash" value first.
In other words, when you redefine "eql?" you have to redefine "hash"
as well.

matz.


Marcel Molina Jr.

unread,
Mar 7, 2005, 9:32:37 PM3/7/05
to

Thanks for the reply. Yes, indeed, I had noted that I needed to define
both hash and eql?. I assumed that that was all that was needed for
uniq to work as expected.

The pertinent bits of code from the example I posted in the original email
are as follows:

def hash
"#@day #@start_time #@end_time"
end

def ==(other_pt)
self.hash == other_pt.hash
end

def eql?(other_pt)
self == other_pt
end

And yet eql? doesn't even seem to be called.

Daniel Berger

unread,
Mar 8, 2005, 12:47:35 AM3/8/05
to
Marcel Molina Jr. wrote:
> On Tue, Mar 08, 2005 at 10:21:00AM +0900, Yukihiro Matsumoto wrote:
> > In message "Re: Customizing Array#uniq by defining eql?"
> > on Tue, 8 Mar 2005 05:16:17 +0900, "Marcel Molina Jr."
<mar...@vernix.org> writes:
> >
> > |PickAxe II's documentation for Array#uniq says,
> > |
> > | Returns a new array by removing duplicate values in _arr_,
where
> > | duplicates are detected by comparing using +eql?+.
> >
> > It creates hash internally to remove redundant values, so that
> > comparison is done by "eql?" but it is filtered by "hash" value
first.
> > In other words, when you redefine "eql?" you have to redefine
"hash"
> > as well.
>
> Thanks for the reply. Yes, indeed, I had noted that I needed to
define
> both hash and eql?. I assumed that that was all that was needed for
> uniq to work as expected.

I agree that this is misleading. Can we clarify this in the
documentation please?

Regards,

Dan

Yukihiro Matsumoto

unread,
Mar 8, 2005, 3:37:44 AM3/8/05
to
Hi,

In message "Re: Customizing Array#uniq by defining eql?"

on Tue, 8 Mar 2005 11:32:37 +0900, "Marcel Molina Jr." <mar...@vernix.org> writes:

|Thanks for the reply. Yes, indeed, I had noted that I needed to define
|both hash and eql?. I assumed that that was all that was needed for
|uniq to work as expected.

hash method should return integer value.

matz.


Reply all
Reply to author
Forward
0 new messages