Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Java (http://www.velocityreviews.com/forums/f30-java.html)
-   -   equals(), Sets, Maps, and degrees of equality (http://www.velocityreviews.com/forums/t805753-equals-sets-maps-and-degrees-of-equality.html)

Sean Mitchell 11-10-2011 02:33 AM

equals(), Sets, Maps, and degrees of equality
 
Anyone ever run into the case where you wish an Object could have more than one equals(), or that Set and Map implementations would let you pass in something like a closure to determine key equality?

It seems to me that objects can be equal in varying degrees. Let's consider a class Dog:

public class Dog {
String breed;
String name;
String age;
}

I may want to have a Set<Dog>, which holds only one Dog of each breed, irrespective of name of age. In this case my equals()/hashcode() would only consider breed.

But I may also want a Mag<Dog, Owner> in which each Dog is made unique by name.

And of course, there is the most intuitive case where I want to use equals() to see if the instances map on all three fields.

I suppose I could create a wrapper class for each purpose which only overrides equals() and hashcode(), but that seems very unsatisfying and inefficient.

I'm interested in how other people have dealt with this. Surprisingly, I have not been able to Google up much on this subject.

Thoughts?

Stefan Ram 11-10-2011 03:07 AM

Re: equals(), Sets, Maps, and degrees of equality
 
Sean Mitchell <sean@mitchwood.com> writes:
>And of course, there is the most intuitive case where I want
>to use equals() to see if the instances map on all three
>fields.


If you know which concept the objects of a class do model,
then you know when two of the are equal. Otherwise, it's
not OOP anymore.

There is nothing wrong with that, but it just does not
seem to fit Java well, which is an OOPL (in a certain sense).


Owen Jacobson 11-10-2011 03:10 AM

Re: equals(), Sets, Maps, and degrees of equality
 
On 2011-11-10 02:33:02 +0000, Sean Mitchell said:

> Anyone ever run into the case where you wish an Object could have more
> than one equals(), or that Set and Map implementations would let you
> pass in something like a closure to determine key equality?


Given the lack of anything sufficiently "like a" closure, until Java 8
if not later, you'll have to live with the options you have.

> It seems to me that objects can be equal in varying degrees. Let's
> consider a class Dog:
>
> public class Dog {
> String breed;
> String name;
> String age;
> }
>
> I may want to have a Set<Dog>, which holds only one Dog of each breed,
> irrespective of name of age. In this case my equals()/hashcode() would
> only consider breed.
>
> But I may also want a Mag<Dog, Owner> in which each Dog is made unique by name.
>
> And of course, there is the most intuitive case where I want to use
> equals() to see if the instances map on all three fields.
>
> I suppose I could create a wrapper class for each purpose which only
> overrides equals() and hashcode(), but that seems very unsatisfying and
> inefficient.


That's one option, and it's not as inefficient (at least in terms of
run time) as you might expect, unless you have several million wrappers
kicking around. It's clunky to write, true.

Another option is the TreeSet and TreeMap classes, which have slightly
worse lookup and insertion complexity guarantees (amortized O(log n) vs
amortized O(1) on lookup, for example) but allow passing a Comparator
that also controls equality tests for that set or map.

-o


Eric Sosman 11-10-2011 03:11 AM

Re: equals(), Sets, Maps, and degrees of equality
 
On 11/9/2011 9:33 PM, Sean Mitchell wrote:
> Anyone ever run into the case where you wish an Object could have more than one equals(), or that Set and Map implementations would let you pass in something like a closure to determine key equality?


IIRC, Common Lisp supports four or five different notions of
"equality." So, yes: The idea of equivalences beyond Java's two has
in fact been deemed useful by someone.

> It seems to me that objects can be equal in varying degrees. Let's consider a class Dog:
>
> public class Dog {
> String breed;
> String name;
> String age;
> }
>
> I may want to have a Set<Dog>, which holds only one Dog of each breed, irrespective of name of age. In this case my equals()/hashcode() would only consider breed.


Seems odd: Why should Fido rather than Rover or Wossname be the
sole representative Cocker Spaniel? Or, why do you want a set of Dogs,
rather than a set of Breeds? Even then I think you'd have difficulty:
Are Schnauzer, Miniature Schnauzer, and Standard Schnauzer one breed or
three?

But okay -- Let's not dwell on the quirks of the example: We'll
suppose that you've got a bunch of objects with multiple attributes,
and you sometimes want to think of them equivalent if their X's match,
while other times you want to pay attention only to their Y's.

> But I may also want a Mag<Dog, Owner> in which each Dog is made unique by name.
>
> And of course, there is the most intuitive case where I want to use equals() to see if the instances map on all three fields.
>
> I suppose I could create a wrapper class for each purpose which only overrides equals() and hashcode(), but that seems very unsatisfying and inefficient.
>
> I'm interested in how other people have dealt with this. Surprisingly, I have not been able to Google up much on this subject.


Two avenues of attack seem plausible. One, as you mention, is to
use a helper class to designate the chosen "identity" attributes. I
think I'd prefer to make it an inner class rather than a wrapper class,
but maybe that just means I'm still too hung up on your dogs and breeds.

The other approach is to implement your own BreedSet that uses
breedEquals() and breedHashCode() instead of the usual methods (and,
of course, documents that fact in large red letters). But this feels
an awful lot like the first step down a slippery slope, one that may
find you implementing umpty-leven specialized variations of Set and
Map and regretting the original choice ...

I'd be inclined to go with the inner class, or perhaps with a
wrapper if there's a reason you can't modify Dog. YMMV.

--
Eric Sosman
esosman@ieee-dot-org.invalid

Volker Borchert 11-10-2011 04:42 AM

Re: equals(), Sets, Maps, and degrees of equality
 
Owen Jacobson wrote:
> > [ class to be used in multiple Maps with different equalities ]
> >
> > I suppose I could create a wrapper class for each purpose which only
> > overrides equals() and hashcode(), but that seems very unsatisfying and
> > inefficient.

>
> That's one option, and it's not as inefficient (at least in terms of
> run time) as you might expect, unless you have several million wrappers
> kicking around. It's clunky to write, true.
>
> Another option is the TreeSet and TreeMap classes, which have slightly
> worse lookup and insertion complexity guarantees (amortized O(log n) vs
> amortized O(1) on lookup, for example) but allow passing a Comparator
> that also controls equality tests for that set or map.


Yet another option is to write your own HashMap.

--

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert <v_borchert@despammed.com>

markspace 11-10-2011 06:43 AM

Re: equals(), Sets, Maps, and degrees of equality
 
On 11/9/2011 7:11 PM, Eric Sosman wrote:

> I'd be inclined to go with the inner class, or perhaps with a
> wrapper if there's a reason you can't modify Dog. YMMV.



I wonder if it's possible to make something like a wrapper, where
instead of one per object you just have a singleton of special cases.

public class Dog {
String name;
String breed;
float weight;

DogComparisonStrategy compare;

public boolean equals( Object o ) {
return compare.equals( this, o );
}

public int hashcode() {
return compare.hashcode( this );
}

}

class CompareByWeight implements DogComparisonStrategy {

public boolean equals( Dog d1, Object o ) {
if( !(o instanceof Dog) ) return false;
Dog d2 = (Dog) o;
return d2.weight == d1.weight;
}

public int hashcode( Dog d ) {
return Float.getFloatbits( d.weight );
}
}


At least you might not need a million of the things, unlike wrapper.
Obviously, you have to be able to modify Dog for this to work.



Sean Mitchell 11-10-2011 02:31 PM

Re: equals(), Sets, Maps, and degrees of equality
 
On Nov 9, 10:11*pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:

>*Seems odd: Why should Fido rather than Rover or Wossname be the
> sole representative Cocker Spaniel?


Just cuz.

Silly example: Father-in-law is going hunting. He has a kennel full of
dogs. Wants a hound and a bird dog. Doesn't care which exact ones.

> Two avenues of attack seem plausible. *One, as you mention, is to
> use a helper class to designate the chosen "identity" attributes. *I
> think I'd prefer to make it an inner class rather than a wrapper class,
> but maybe that just means I'm still too hung up on your dogs and breeds.


Hmmm. This is interesting. How would it work? So, I'd have an inner
class for each type of equality I need, basically exposing its parent
and providing the desired equals()? Think I'll play around with that
idea.


> * * *The other approach is to implement your own BreedSet that uses
> breedEquals() and breedHashCode() instead of the usual methods (and,
> of course, documents that fact in large red letters). *But this feels
> an awful lot like the first step down a slippery slope, one that may
> find you implementing umpty-leven specialized variations of Set and
> Map and regretting the original choice ...


Yes, as I said in my reply to Owen (which I think I accidentally sent
as reply to author), if possible I'd rather use smarter people's work
than write my own implementation. His TreeSet/TrreMap proposal is my
favourite solution so far.


Cheers,

Sean

Sean Mitchell 11-10-2011 02:33 PM

Re: equals(), Sets, Maps, and degrees of equality
 
On Nov 10, 1:43*am, markspace <-@.> wrote:

> I wonder if it's possible to make something like a wrapper, where
> instead of one per object you just have a singleton of special cases.


Possible, but I could see a lot of concurrency issue arising. Might
work well in a single threaded application.

markspace 11-10-2011 03:21 PM

Re: equals(), Sets, Maps, and degrees of equality
 
On 11/10/2011 6:33 AM, Sean Mitchell wrote:
> On Nov 10, 1:43 am, markspace<-@.> wrote:
>
>> I wonder if it's possible to make something like a wrapper, where
>> instead of one per object you just have a singleton of special cases.

>
> Possible, but I could see a lot of concurrency issue arising. Might
> work well in a single threaded application.



What? Why? There's no concurrency issues there. There's no state
beyond what is in the Dog object. Method call != concurrency issue. In
fact it's the opposite, method calls are inherently thread safe.

If you need concurrency, you add it to the Dog object.



Sean Mitchell 11-10-2011 03:29 PM

Re: equals(), Sets, Maps, and degrees of equality
 
On Nov 10, 10:21*am, markspace <-@.> wrote:

> > Possible, but I could see a lot of concurrency issue arising. Might
> > work well in a single threaded application.

>
> What? *Why? *There's no concurrency issues there. *There's no state
> beyond what is in the Dog object. *Method call != concurrency issue. *In
> fact it's the opposite, method calls are inherently thread safe.
>
> If you need concurrency, you add it to the Dog object.


Maybe I don't understand what you are proposing. It sounds like you
want a singleton wrapper, into which I stuff my Dog, before I put him
into my Set/Map.

Please elaborate.

Cheers,

Sean


All times are GMT. The time now is 10:41 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.