Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #9813 > unrolled thread

equals(), Sets, Maps, and degrees of equality

Started bySean Mitchell <sean@mitchwood.com>
First post2011-11-09 18:33 -0800
Last post2011-11-16 09:15 -0800
Articles 20 on this page of 25 — 9 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-09 18:33 -0800
    Re: equals(), Sets, Maps, and degrees of equality Owen Jacobson <angrybaldguy@gmail.com> - 2011-11-09 22:10 -0500
      Re: equals(), Sets, Maps, and degrees of equality v_borchert@despammed.com (Volker Borchert) - 2011-11-10 04:42 +0000
    Re: equals(), Sets, Maps, and degrees of equality Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-11-09 22:11 -0500
      Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-09 22:43 -0800
        Re: equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-10 06:33 -0800
          Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-10 07:21 -0800
            Re: equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-10 07:29 -0800
              Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-10 10:27 -0800
              Re: equals(), Sets, Maps, and degrees of equality Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-11-10 20:58 -0500
                Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-10 19:07 -0800
                  Re: equals(), Sets, Maps, and degrees of equality Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-11-10 23:24 -0500
                    Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-10 20:55 -0800
                Re: equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-11 10:27 -0800
                  Re: equals(), Sets, Maps, and degrees of equality Lew <lewbloch@gmail.com> - 2011-11-11 14:21 -0800
      Re: equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-10 06:31 -0800
        Re: equals(), Sets, Maps, and degrees of equality Daniel Pitts <newsgroup.nospam@virtualinfinity.net> - 2011-11-10 11:27 -0800
    Re: equals(), Sets, Maps, and degrees of equality Roedy Green <see_website@mindprod.com.invalid> - 2011-11-10 16:01 -0800
    Re: equals(), Sets, Maps, and degrees of equality Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2011-11-11 09:08 +0000
      Re: equals(), Sets, Maps, and degrees of equality Lew <lewbloch@gmail.com> - 2011-11-11 07:27 -0800
        Re: equals(), Sets, Maps, and degrees of equality Sean Mitchell <sean@mitchwood.com> - 2011-11-11 10:28 -0800
          Re: equals(), Sets, Maps, and degrees of equality Lew <lewbloch@gmail.com> - 2011-11-11 14:22 -0800
            Re: equals(), Sets, Maps, and degrees of equality markspace <-@.> - 2011-11-11 15:19 -0800
            Re: equals(), Sets, Maps, and degrees of equality Lew <lewbloch@gmail.com> - 2011-11-13 21:18 -0800
              Re: equals(), Sets, Maps, and degrees of equality Lew <lewbloch@gmail.com> - 2011-11-16 09:15 -0800

Page 1 of 2  [1] 2  Next page →


#9813 — equals(), Sets, Maps, and degrees of equality

FromSean Mitchell <sean@mitchwood.com>
Date2011-11-09 18:33 -0800
Subjectequals(), Sets, Maps, and degrees of equality
Message-ID<24123649.762.1320892382934.JavaMail.geo-discussion-forums@vbmh5>
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?

[toc] | [next] | [standalone]


#9815

FromOwen Jacobson <angrybaldguy@gmail.com>
Date2011-11-09 22:10 -0500
Message-ID<2011110922100694284-angrybaldguy@gmailcom>
In reply to#9813
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

[toc] | [prev] | [next] | [standalone]


#9817

Fromv_borchert@despammed.com (Volker Borchert)
Date2011-11-10 04:42 +0000
Message-ID<j9fko1$nrr$1@Gaia.teknon.de>
In reply to#9815
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>

[toc] | [prev] | [next] | [standalone]


#9816

FromEric Sosman <esosman@ieee-dot-org.invalid>
Date2011-11-09 22:11 -0500
Message-ID<j9ffe1$3k9$1@dont-email.me>
In reply to#9813
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

[toc] | [prev] | [next] | [standalone]


#9821

Frommarkspace <-@.>
Date2011-11-09 22:43 -0800
Message-ID<j9frqs$pbk$1@dont-email.me>
In reply to#9816
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.

[toc] | [prev] | [next] | [standalone]


#9823

FromSean Mitchell <sean@mitchwood.com>
Date2011-11-10 06:33 -0800
Message-ID<663d43b1-2c58-40ea-90d5-d46b8ae821e5@cc2g2000vbb.googlegroups.com>
In reply to#9821
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.

[toc] | [prev] | [next] | [standalone]


#9824

Frommarkspace <-@.>
Date2011-11-10 07:21 -0800
Message-ID<j9gq5d$ue6$1@dont-email.me>
In reply to#9823
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.

[toc] | [prev] | [next] | [standalone]


#9825

FromSean Mitchell <sean@mitchwood.com>
Date2011-11-10 07:29 -0800
Message-ID<5a705514-4b5e-48c2-8984-83e3b62b23b9@y7g2000vbe.googlegroups.com>
In reply to#9824
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

[toc] | [prev] | [next] | [standalone]


#9830

Frommarkspace <-@.>
Date2011-11-10 10:27 -0800
Message-ID<j9h51n$ckf$1@dont-email.me>
In reply to#9825
On 11/10/2011 7:29 AM, Sean Mitchell wrote:
>
> 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.


Yes, although I'd call that the opposite of a wrapper.  It's a Strategy 
pattern.

But there's no additional concurrency issues created by using it.  Just 
use Dog normally.  Your Dog class isn't thread safe as you wrote it, so 
there's no additional issues.

If you do require thread safety, protecting the field I added is no 
different than protecting the other fields in Dog.  Do it exactly the 
same way.  (How you do so may vary depending on your needs for the 
class, so there's rather more options than I'd care to go into.  Read a 
good book on Java Concurrency or read the JLS for ideas.)

[toc] | [prev] | [next] | [standalone]


#9840

FromEric Sosman <esosman@ieee-dot-org.invalid>
Date2011-11-10 20:58 -0500
Message-ID<j9hvhf$r4p$1@dont-email.me>
In reply to#9825
On 11/10/2011 10:29 AM, Sean Mitchell wrote:
> 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.

     I think "concurrency issues" might not be the best description,
but there are certainly drawbacks to markspace's suggestion.  Back
to your original post: You wanted a Dog whose breed (only) would
govern its membership in a Set<Dog> but whose name (only) would
matter for a Map<Dog,Owner>.  markspace's idea of endowing each Dog
with a DogComparisonStrategy wouldn't work if the same Dog instance
could be a member of the Set *and* a key in the Map: You'd need to
visit every Dog and reset its DogComparisonStrategy before doing
any operation on either the Set or the Map.  (Strictly speaking,
you'd only need to visit the Dogs that participated in the relevant
data structure -- but since it would be at best dubious to traverse
a Set or Map whose Dogs were in the wrong state you'd need a third
Collection<Dog> that would not use the DogComparisonStrategy at all.)

     The notion of making Breed and Name inner classes of Dog seems
more and more attractive:

	class Dog {
	    class Breed { ... };
	    class Name { ... };
	    private Breed breed;
	    private Name name;
	    ...
	}

The wrapper approach could also work, and would be necessary if Dog
weren't alterable:

	class Dog {
	    private String name;
	    private String breed;
	    ...
	}

	class DogByBreed {
	    private Dog dog;
	    ...
	    public int hashCode() {
	        return dog.getBreed().hashCode();
	    }
	    ...
	}

	class DogByName {
	    private Dog dog;
	    ...
	    public int hashCode() {
	        return dog.getName().hashCode();
	    }
	    ...
	}

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

[toc] | [prev] | [next] | [standalone]


#9841

Frommarkspace <-@.>
Date2011-11-10 19:07 -0800
Message-ID<j9i3he$ej9$1@dont-email.me>
In reply to#9840
On 11/10/2011 5:58 PM, Eric Sosman wrote:

>  markspace's idea of endowing each Dog
> with a DogComparisonStrategy wouldn't work if the same Dog instance
> could be a member of the Set *and* a key in the Map:


Right.  It's really not that different than making subclasses to handle 
different schemes.  It just tries to be a bit more pithy about how it 
does it.  I'm mostly just tossing it out there to spur a little thought 
and discussion.  The "concurrency" comment caught me off guard, I'll admit.

I actually like the suggestion to use a Tree with a supplied Comparator. 
  It seems closest to what the OP really needs.  Second choice is just 
use the wrappers.  Third choice: if profiling shows wrappers or the Tree 
slowing things down, implement custom Map/Set classes to do exactly 
what's needed.


> You'd need to
> visit every Dog and reset its DogComparisonStrategy before doing


Stuff like that probably isn't kosher.  What if some external process 
affects the the Map or Set right in the middle of iterating over its 
contents?  This could be really ugly and a real maintenance hazard.


[toc] | [prev] | [next] | [standalone]


#9842

FromEric Sosman <esosman@ieee-dot-org.invalid>
Date2011-11-10 23:24 -0500
Message-ID<j9i856$5a4$1@dont-email.me>
In reply to#9841
On 11/10/2011 10:07 PM, markspace wrote:
> On 11/10/2011 5:58 PM, Eric Sosman wrote:
>
>> markspace's idea of endowing each Dog
>> with a DogComparisonStrategy wouldn't work if the same Dog instance
>> could be a member of the Set *and* a key in the Map:
>
>
> Right. It's really not that different than making subclasses to handle
> different schemes.

     It seems strikingly different to me.  Your suggestion is that
a Dog could dictate which of several hashCode/equals pairs to use,
but any particular Dog instance could select only one pair at a time.
With inner classes or wrappers, a single Dog instance could present
multiple aspects simultaneously and could participate simultaneously
in multiple collections based on those different key-nesses.

     Look at it this way: In your formulation, the Dog instance says
"I am known by my breed" or "I am known by my name," and every Set<Dog>
or Map<Dog,Owner> has to accept the Dog's own decision.  With inner
classes or wrappers, the Dog says "I am a Beagle and my name is Snoopy,"
and each Set<Dog.Breed> or Map<Dog.Name,Owner> makes its own choice
about which aspect counts.  In one case the Dog dictates its aspect;
in the other the collection chooses the aspect it cares about.

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

[toc] | [prev] | [next] | [standalone]


#9843

Frommarkspace <-@.>
Date2011-11-10 20:55 -0800
Message-ID<j9i9t1$d5u$1@dont-email.me>
In reply to#9842
On 11/10/2011 8:24 PM, Eric Sosman wrote:

> On 11/10/2011 10:07 PM, markspace wrote:
>> Right. It's really not that different than making subclasses to handle
>> different schemes.

>
> It seems strikingly different to me. Your suggestion is that
> a Dog could dictate which of several hashCode/equals pairs to use,
> but any particular Dog instance could select only one pair at a time.
> With inner classes or wrappers, a single Dog instance could present
> multiple aspects simultaneously and could participate simultaneously
> in multiple collections based on those different key-nesses.


Oh I see.  The wrapper being a subclass of Dog.  I was thinking of 
comparing my Strategy pattern with subclasses which implemented specific 
behavior.

class Dog { .. some fields .. }

class DogSortedByName extends Dog {...}

class DogSortedByBreed extends Dog {...}

The strategy pattern is similar, because we really can't change a class 
of Dog once its used.  In extraordinary cases we could, if the object 
could be removed from a given collection completely, then we could 
change the its strategy and add it to another collection, but this may 
not be useful or practical.

The wrapper pattern is definitely more flexible, at the cost of needing 
one wrapper object for each Dog object.  The Strategy pattern is less 
flexible, but only needs one Strategy object per strategy (in this case 
anyway), and doesn't seem to buy us much over concrete subclasses. 
Given that we actually don't know that much about the OP's problem, I 
thought it would be interesting to speculate on some different solutions.

[toc] | [prev] | [next] | [standalone]


#9854

FromSean Mitchell <sean@mitchwood.com>
Date2011-11-11 10:27 -0800
Message-ID<0ac33ed5-19cc-4654-ba74-8df90262cd51@cu3g2000vbb.googlegroups.com>
In reply to#9840
On Nov 10, 8:58 pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> On 11/10/2011 10:29 AM, Sean Mitchell wrote:

> I think "concurrency issues" might not be the best description,

No, probably not. But I think you see where my reluctance to follow
that approach lies.

> The notion of making Breed and Name inner classes of Dog seems
> more and more attractive:

[snip]

> The wrapper approach could also work, and would be necessary if Dog
> weren't alterable


I think, fundamentally, that is the problem. I don't think that Dog
or any subclass of Dog should have to be in any way concerned with
how I want to use him in a collection. Although IMO it is reasonable
for Dog to know whether or nor he is the same as another Dog in all
the ways that are important to Dogs.

The core of the issue for me is that the most commonly used
implementations of Set (possibly Map was a poor example, as has been
illustrated by Andreas and others) rely solely on the object's
equals() to determine equivalence.

TreeSet will take a Comparator as pointed out, and so probably this
is good enough, but it seems a little hackish to use a Comparator,
and a SortedSet to solve a problem of equality (or perhaps,
equivalency).


Sean

[toc] | [prev] | [next] | [standalone]


#9858

FromLew <lewbloch@gmail.com>
Date2011-11-11 14:21 -0800
Message-ID<364616.2083.1321050103231.JavaMail.geo-discussion-forums@prms22>
In reply to#9854
Sean Mitchell wrote:
...
> I think, fundamentally, that is the problem. I don't think that Dog
> or any subclass of Dog should have to be in any way concerned with
> how I want to use him in a collection. Although IMO it is reasonable
> for Dog to know whether or nor he is the same as another Dog in all
> the ways that are important to Dogs.
> 
> The core of the issue for me is that the most commonly used
> implementations of Set (possibly Map was a poor example, as has been
> illustrated by Andreas and others) rely solely on the object's
> equals() to determine equivalence.

The core of the issue is that you want to use the wrong entity as your key.

The fault, dear Brutus, lies not in our 'equals()' method but in ourselves.

> TreeSet will take a Comparator as pointed out, and so probably this
> is good enough, but it seems a little hackish to use a Comparator,
> and a SortedSet to solve a problem of equality (or perhaps,
> equivalency).


"Seems"?  That's a pretty subjective statement without any engineering basis.  What is "hackish"?  That is the standard solution and why 'Comparator' exists in the API.  The burden of proof is on the one claiming "hackishness", along with the burden of definition for such a vague, subjective term, especially when paired with the hand-waving, responsibility-ducking "seems".

I'm here to tell you, there's nothing hackish about using a 'Comparator'.  That's a strange sentiment coming from someone who wants to hackishly use the 'Dog' class for a key where he means 'Breed'.  Maybe if your model wasn't so tangled and illogical you'd have an easier time of it.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#9822

FromSean Mitchell <sean@mitchwood.com>
Date2011-11-10 06:31 -0800
Message-ID<aa35f1af-81ac-4369-a9f3-5c7c5e161f39@y7g2000vbe.googlegroups.com>
In reply to#9816
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

[toc] | [prev] | [next] | [standalone]


#9831

FromDaniel Pitts <newsgroup.nospam@virtualinfinity.net>
Date2011-11-10 11:27 -0800
Message-ID<0BVuq.18371$Mg.11636@newsfe13.iad>
In reply to#9822
On 11/10/11 6:31 AM, Sean Mitchell wrote:
> 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
I've often wanted the equivalent of "Comparator" for the Hash 
implementations of Map/Set.

public interface HashStrategy<T> {
    int hash(T object);
    boolean equivalent(T a, T b);
}


public class DefaultHashStrategy<T> extends HashStrategy<T> {
    public int hash(T object) {
       return object == null ? 0 : object.hashCode();
    }

    public boolean equivalent(T a, T b) {
       return a == null ? b == null : a.equals(b);
    }
}


public class HashMap<K,V> implements Map<K,V> {
     private final HashStrategy<? super K> hashStrategy;

     public HashMap(HashStrategy<? super K> hashStrategy) {
        this.hashStrategy = hashStrategy;
     }
     public HashMap() {
        this(new DefaultHashStrategy<K>());
     }
     // ... the rest of the HashMap implementation.
}

[toc] | [prev] | [next] | [standalone]


#9838

FromRoedy Green <see_website@mindprod.com.invalid>
Date2011-11-10 16:01 -0800
Message-ID<9epob7h42gjlqjrjrh29r1g3p37llfqeio@4ax.com>
In reply to#9813
On Wed, 9 Nov 2011 18:33:02 -0800 (PST), Sean Mitchell
<sean@mitchwood.com> wrote, quoted or indirectly quoted someone who
said :

>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.

Hmm.  You have the ability to override equals so it behaves
differently classes that inherit from each other. But for all
practical purposes all but one version is inaccessible.

Let's say you wrote three equals methods. and named them

equalBySpecies
equalByOwener
equalByCallName

Now you could write something like this

public boolean equals ( Object o )
   {
   switch (how )
     {
     case SPECIES:  return equalBySpecies ( o) ; 
     case OWNER: return equalByOwner(o);
     case CALLNAME : return equalByCallName(o);
     default: throw new IllegalArgumentException ("Bad how sort" );
     }
   }

Now the problem is, how do get the value of how into the equals
method?  It could be a static, but then you could not have separate
Collections running at once. Perhaps you have to extend the Collection
class to store it there.  That still does not solve the problem of how
the Object knows for this invocation of equals who which collection is
asking. Gaak! would it have to analyse the stack?

But then, you can pass a Comparator can't you to some collections.
Then the individual objects don't need to know how they are being
compared. It is not their code.




     
   }
-- 
Roedy Green Canadian Mind Products
http://mindprod.com
HP makes a dozens of quite different printer models all called the 1200.
Mine has a GO button, which is not needed since it runs anyway if nothing
is blocking it.  However, it has no STOP, FLUSH or OFF button.

[toc] | [prev] | [next] | [standalone]


#9844

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2011-11-11 09:08 +0000
Message-ID<slrnjbppgl.fvg.avl@gamma.logic.tuwien.ac.at>
In reply to#9813
Sean Mitchell <sean@mitchwood.com> 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?

Yep, I also noticed this lack in the context of "orthogonality".
I just still haven't found any actual practical use for it.

> 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,

In that case, I'd use a Map<String,Dog>, which would be keyed by the breed
name itself, rather than by an arbitrary dog of that breed.

Probably, I'd even create a class Breed, that would encapsulate some more
properties along with the name, and then use the Breed class as key.

For the example at hand, this would allow filling the structure with breeds
that are "requested" (initially associated with null Dog), then some other
part of the code could pick an appropriate Dog for each requested Breed.

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

That doesn't make sense to me, because the owner would rather be a property
of the dog(*), than of its name. Who's the owner of "any dog called Rufus", btw?

*: natural language is sometimes quite at odds with modelling language. :-)

[toc] | [prev] | [next] | [standalone]


#9847

FromLew <lewbloch@gmail.com>
Date2011-11-11 07:27 -0800
Message-ID<4407931.1762.1321025241857.JavaMail.geo-discussion-forums@prep8>
In reply to#9844
Andreas Leitgeb wrote:
> 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?
> 
> Yep, I also noticed this lack in the context of "orthogonality".
> I just still haven't found any actual practical use for it.
> 
>> 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,

This is terrible modeling.

> In that case, I'd use a Map<String,Dog>, which would be keyed by the breed
> name itself, rather than by an arbitrary dog of that breed.
> 
> Probably, I'd even create a class Breed, that would encapsulate some more
> properties along with the name, and then use the Breed class as key.

+
This is the way to go.

> For the example at hand, this would allow filling the structure with breeds
> that are "requested" (initially associated with null Dog), then some other
> part of the code could pick an appropriate Dog for each requested Breed.
> 
>> But I may also want a Map<Dog, Owner> in which each Dog is made unique
>> by name.
> 
> That doesn't make sense to me, because the owner would rather be a property
> of the dog(*), than of its name. Who's the owner of "any dog called Rufus", btw?
> 
> *: natural language is sometimes quite at odds with modelling language. :-)

Andreas is on to something here.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.java.programmer


csiph-web