How to implement Comparable so it is consistent with identity-equality





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







17















I have a class for which equality (as per equals()) must be defined by the object identity, i.e. this == other.



I want to implement Comparable to order such objects (say by some getName() property). To be consistent with equals(), compareTo() must not return 0, even if two objects have the same name.



Is there a way to compare object identities in the sense of compareTo? I could compare System.identityHashCode(o), but that would still return 0 in case of hash collisions.










share|improve this question

























  • compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

    – Lino
    Apr 1 at 8:18






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    Apr 1 at 8:21











  • Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

    – Ricky Mo
    Apr 1 at 8:25











  • @RickyMo right.

    – Balz Guenat
    Apr 1 at 8:31






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    Apr 1 at 9:40


















17















I have a class for which equality (as per equals()) must be defined by the object identity, i.e. this == other.



I want to implement Comparable to order such objects (say by some getName() property). To be consistent with equals(), compareTo() must not return 0, even if two objects have the same name.



Is there a way to compare object identities in the sense of compareTo? I could compare System.identityHashCode(o), but that would still return 0 in case of hash collisions.










share|improve this question

























  • compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

    – Lino
    Apr 1 at 8:18






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    Apr 1 at 8:21











  • Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

    – Ricky Mo
    Apr 1 at 8:25











  • @RickyMo right.

    – Balz Guenat
    Apr 1 at 8:31






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    Apr 1 at 9:40














17












17








17


0






I have a class for which equality (as per equals()) must be defined by the object identity, i.e. this == other.



I want to implement Comparable to order such objects (say by some getName() property). To be consistent with equals(), compareTo() must not return 0, even if two objects have the same name.



Is there a way to compare object identities in the sense of compareTo? I could compare System.identityHashCode(o), but that would still return 0 in case of hash collisions.










share|improve this question
















I have a class for which equality (as per equals()) must be defined by the object identity, i.e. this == other.



I want to implement Comparable to order such objects (say by some getName() property). To be consistent with equals(), compareTo() must not return 0, even if two objects have the same name.



Is there a way to compare object identities in the sense of compareTo? I could compare System.identityHashCode(o), but that would still return 0 in case of hash collisions.







java equals comparator comparable






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 1 at 18:46









Peter Mortensen

13.9k1987113




13.9k1987113










asked Apr 1 at 8:10









Balz GuenatBalz Guenat

4572419




4572419













  • compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

    – Lino
    Apr 1 at 8:18






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    Apr 1 at 8:21











  • Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

    – Ricky Mo
    Apr 1 at 8:25











  • @RickyMo right.

    – Balz Guenat
    Apr 1 at 8:31






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    Apr 1 at 9:40



















  • compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

    – Lino
    Apr 1 at 8:18






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    Apr 1 at 8:21











  • Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

    – Ricky Mo
    Apr 1 at 8:25











  • @RickyMo right.

    – Balz Guenat
    Apr 1 at 8:31






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    Apr 1 at 9:40

















compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

– Lino
Apr 1 at 8:18





compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a compareTo would be unusable

– Lino
Apr 1 at 8:18




3




3





Which clause of the contract would be broken exactly?

– Balz Guenat
Apr 1 at 8:21





Which clause of the contract would be broken exactly?

– Balz Guenat
Apr 1 at 8:21













Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

– Ricky Mo
Apr 1 at 8:25





Did you mean you want when A and B have getName() equal, you don't care whether A > B or B > A, but you want consistent result i.e. if for once A > B is true, then A > B is always true throughout the whole process lifetime?

– Ricky Mo
Apr 1 at 8:25













@RickyMo right.

– Balz Guenat
Apr 1 at 8:31





@RickyMo right.

– Balz Guenat
Apr 1 at 8:31




3




3





@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

– Haem
Apr 1 at 9:40





@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

– Haem
Apr 1 at 9:40












6 Answers
6






active

oldest

votes


















31














I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.



If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.



In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.






share|improve this answer



















  • 8





    A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

    – khelwood
    Apr 1 at 8:23






  • 2





    Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

    – Balz Guenat
    Apr 1 at 8:38











  • @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

    – GhostCat
    Apr 1 at 8:46






  • 1





    @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

    – GhostCat
    Apr 1 at 12:15






  • 1





    @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

    – Voo
    Apr 1 at 14:59





















5














You could add a second property (say int id or long id) which would be unique for each instance of your class (you can have a static counter variable and use it to initialize the id in your constructor).



Then your compareTo method can first compare the names, and if the names are equal, compare the ids.



Since each instance has a different id, compareTo will never return 0.






share|improve this answer



















  • 1





    This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

    – Balz Guenat
    Apr 1 at 8:20











  • @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

    – Eran
    Apr 1 at 8:37






  • 1





    "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

    – Balz Guenat
    Apr 1 at 8:45











  • @BalzGuenat good point.

    – Eran
    Apr 1 at 8:47






  • 1





    The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

    – kutschkem
    Apr 1 at 10:07





















5














By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.



If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.






share|improve this answer


























  • You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    Apr 1 at 15:43











  • @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

    – Tezra
    Apr 1 at 16:06



















1














While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".



Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)



import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;

public class Test implements Comparable<Test>{

private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();

private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}

return antiuniverseProp.get(i);
}

@Override
public int compareTo(Test o) {
if(this == o)
return 0;

int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;

//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;

//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;

for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;

temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}

// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}

}





share|improve this answer

































    0














    Assuming that with two objects with same name, if equals() returns false then compareTo() should not return 0. If this is what you want to do then following can help:




    • Override hashcode() and make sure it doesn't rely solely on name

    • Implement compareTo() as follows:


    public void compareTo(MyObject object) {
    this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
    }





    share|improve this answer
























    • Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

      – Balz Guenat
      Apr 1 at 8:22











    • That is the reason why I advised overriding hashcode() and make it rely not just on name.

      – Darshan Mehta
      Apr 1 at 8:26











    • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

      – Balz Guenat
      Apr 1 at 8:33



















    0














    You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.



    private static Set<Pair<C, C> collisions = ...;

    @Override
    public boolean equals(C other) {
    return this == other;
    }

    @Override
    public int compareTo(C other) {
    ...
    if (this == other) {
    return 0
    }
    if (super.equals(other)) {
    // Some stable order would be fine:
    // return either -1 or 1
    if (collisions.contains(new Pair(other, this)) {
    return 1;
    } else if (!collisions.contains(new Pair(this, other)) {
    collisions.add(new Par(this, other));
    }
    return 1;
    }
    ...
    }


    So go with the answer of Eran or put the requirement as such in question.




    • One might consider the overhead of non-identical 0 comparisons neglectable.

    • One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.






    share|improve this answer





















    • 1





      This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

      – Yakk - Adam Nevraumont
      Apr 1 at 15:44













    • @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

      – Joop Eggen
      Apr 1 at 15:55






    • 1





      Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

      – Voo
      Apr 1 at 16:31











    • @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

      – Tezra
      Apr 2 at 19:18











    • @Tezra "Made to work", agreed that the current solution is not going to be correct.

      – Voo
      Apr 2 at 19:27












    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    6 Answers
    6






    active

    oldest

    votes








    6 Answers
    6






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    31














    I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.



    If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.



    In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.






    share|improve this answer



















    • 8





      A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

      – khelwood
      Apr 1 at 8:23






    • 2





      Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

      – Balz Guenat
      Apr 1 at 8:38











    • @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

      – GhostCat
      Apr 1 at 8:46






    • 1





      @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

      – GhostCat
      Apr 1 at 12:15






    • 1





      @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

      – Voo
      Apr 1 at 14:59


















    31














    I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.



    If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.



    In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.






    share|improve this answer



















    • 8





      A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

      – khelwood
      Apr 1 at 8:23






    • 2





      Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

      – Balz Guenat
      Apr 1 at 8:38











    • @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

      – GhostCat
      Apr 1 at 8:46






    • 1





      @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

      – GhostCat
      Apr 1 at 12:15






    • 1





      @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

      – Voo
      Apr 1 at 14:59
















    31












    31








    31







    I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.



    If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.



    In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.






    share|improve this answer













    I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.



    If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.



    In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Apr 1 at 8:19









    GhostCatGhostCat

    95.9k1794161




    95.9k1794161








    • 8





      A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

      – khelwood
      Apr 1 at 8:23






    • 2





      Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

      – Balz Guenat
      Apr 1 at 8:38











    • @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

      – GhostCat
      Apr 1 at 8:46






    • 1





      @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

      – GhostCat
      Apr 1 at 12:15






    • 1





      @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

      – Voo
      Apr 1 at 14:59
















    • 8





      A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

      – khelwood
      Apr 1 at 8:23






    • 2





      Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

      – Balz Guenat
      Apr 1 at 8:38











    • @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

      – GhostCat
      Apr 1 at 8:46






    • 1





      @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

      – GhostCat
      Apr 1 at 12:15






    • 1





      @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

      – Voo
      Apr 1 at 14:59










    8




    8





    A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

    – khelwood
    Apr 1 at 8:23





    A comparator seems like a non-broken solution. Even if the expectation of Comparable is that compare==0 only when the two objects are equal, a comparator does not have that expectation.

    – khelwood
    Apr 1 at 8:23




    2




    2





    Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

    – Balz Guenat
    Apr 1 at 8:38





    Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".

    – Balz Guenat
    Apr 1 at 8:38













    @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

    – GhostCat
    Apr 1 at 8:46





    @BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)

    – GhostCat
    Apr 1 at 8:46




    1




    1





    @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

    – GhostCat
    Apr 1 at 12:15





    @BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?

    – GhostCat
    Apr 1 at 12:15




    1




    1





    @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

    – Voo
    Apr 1 at 14:59







    @Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your equals consistent with compareTo you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.

    – Voo
    Apr 1 at 14:59















    5














    You could add a second property (say int id or long id) which would be unique for each instance of your class (you can have a static counter variable and use it to initialize the id in your constructor).



    Then your compareTo method can first compare the names, and if the names are equal, compare the ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer



















    • 1





      This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

      – Balz Guenat
      Apr 1 at 8:20











    • @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

      – Eran
      Apr 1 at 8:37






    • 1





      "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

      – Balz Guenat
      Apr 1 at 8:45











    • @BalzGuenat good point.

      – Eran
      Apr 1 at 8:47






    • 1





      The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

      – kutschkem
      Apr 1 at 10:07


















    5














    You could add a second property (say int id or long id) which would be unique for each instance of your class (you can have a static counter variable and use it to initialize the id in your constructor).



    Then your compareTo method can first compare the names, and if the names are equal, compare the ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer



















    • 1





      This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

      – Balz Guenat
      Apr 1 at 8:20











    • @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

      – Eran
      Apr 1 at 8:37






    • 1





      "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

      – Balz Guenat
      Apr 1 at 8:45











    • @BalzGuenat good point.

      – Eran
      Apr 1 at 8:47






    • 1





      The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

      – kutschkem
      Apr 1 at 10:07
















    5












    5








    5







    You could add a second property (say int id or long id) which would be unique for each instance of your class (you can have a static counter variable and use it to initialize the id in your constructor).



    Then your compareTo method can first compare the names, and if the names are equal, compare the ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer













    You could add a second property (say int id or long id) which would be unique for each instance of your class (you can have a static counter variable and use it to initialize the id in your constructor).



    Then your compareTo method can first compare the names, and if the names are equal, compare the ids.



    Since each instance has a different id, compareTo will never return 0.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Apr 1 at 8:16









    EranEran

    292k37481564




    292k37481564








    • 1





      This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

      – Balz Guenat
      Apr 1 at 8:20











    • @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

      – Eran
      Apr 1 at 8:37






    • 1





      "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

      – Balz Guenat
      Apr 1 at 8:45











    • @BalzGuenat good point.

      – Eran
      Apr 1 at 8:47






    • 1





      The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

      – kutschkem
      Apr 1 at 10:07
















    • 1





      This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

      – Balz Guenat
      Apr 1 at 8:20











    • @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

      – Eran
      Apr 1 at 8:37






    • 1





      "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

      – Balz Guenat
      Apr 1 at 8:45











    • @BalzGuenat good point.

      – Eran
      Apr 1 at 8:47






    • 1





      The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

      – kutschkem
      Apr 1 at 10:07










    1




    1





    This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

    – Balz Guenat
    Apr 1 at 8:20





    This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.

    – Balz Guenat
    Apr 1 at 8:20













    @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

    – Eran
    Apr 1 at 8:37





    @BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the id would have to be serialized.

    – Eran
    Apr 1 at 8:37




    1




    1





    "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

    – Balz Guenat
    Apr 1 at 8:45





    "the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.

    – Balz Guenat
    Apr 1 at 8:45













    @BalzGuenat good point.

    – Eran
    Apr 1 at 8:47





    @BalzGuenat good point.

    – Eran
    Apr 1 at 8:47




    1




    1





    The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

    – kutschkem
    Apr 1 at 10:07







    The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.

    – kutschkem
    Apr 1 at 10:07













    5














    By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.



    If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.






    share|improve this answer


























    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      Apr 1 at 15:43











    • @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

      – Tezra
      Apr 1 at 16:06
















    5














    By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.



    If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.






    share|improve this answer


























    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      Apr 1 at 15:43











    • @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

      – Tezra
      Apr 1 at 16:06














    5












    5








    5







    By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.



    If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.






    share|improve this answer















    By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.



    If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 1 at 16:02

























    answered Apr 1 at 14:57









    TezraTezra

    5,23321244




    5,23321244













    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      Apr 1 at 15:43











    • @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

      – Tezra
      Apr 1 at 16:06



















    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      Apr 1 at 15:43











    • @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

      – Tezra
      Apr 1 at 16:06

















    You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    Apr 1 at 15:43





    You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    Apr 1 at 15:43













    @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

    – Tezra
    Apr 1 at 16:06





    @Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.

    – Tezra
    Apr 1 at 16:06











    1














    While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".



    Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)



    import java.time.Instant;
    import java.util.ArrayList;
    import java.util.UUID;

    public class Test implements Comparable<Test>{

    private final UUID antiCollisionProp = UUID.randomUUID();
    private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();

    private UUID getParanoiaLevelId(int i) {
    while(antiuniverseProp.size() < i) {
    antiuniverseProp.add(UUID.randomUUID());
    }

    return antiuniverseProp.get(i);
    }

    @Override
    public int compareTo(Test o) {
    if(this == o)
    return 0;

    int temp = System.identityHashCode(this) - System.identityHashCode(o);
    if(temp != 0)
    return temp;

    //If the universe hates you
    temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
    if(temp != 0)
    return temp;

    //If the universe is activly out to get you
    temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
    if(temp != 0)
    return temp;

    for(int i = 0; i < Integer.MAX_VALUE; i++) {
    UUID id1 = this.getParanoiaLevelId(i);
    UUID id2 = o.getParanoiaLevelId(i);
    temp = id1.compareTo(id2);
    if(temp != 0)
    return temp;

    temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
    if(temp != 0)
    return temp;
    }

    // If you reach this point, I have no idea what you did to deserve this
    throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
    }

    }





    share|improve this answer






























      1














      While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".



      Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)



      import java.time.Instant;
      import java.util.ArrayList;
      import java.util.UUID;

      public class Test implements Comparable<Test>{

      private final UUID antiCollisionProp = UUID.randomUUID();
      private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();

      private UUID getParanoiaLevelId(int i) {
      while(antiuniverseProp.size() < i) {
      antiuniverseProp.add(UUID.randomUUID());
      }

      return antiuniverseProp.get(i);
      }

      @Override
      public int compareTo(Test o) {
      if(this == o)
      return 0;

      int temp = System.identityHashCode(this) - System.identityHashCode(o);
      if(temp != 0)
      return temp;

      //If the universe hates you
      temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
      if(temp != 0)
      return temp;

      //If the universe is activly out to get you
      temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
      if(temp != 0)
      return temp;

      for(int i = 0; i < Integer.MAX_VALUE; i++) {
      UUID id1 = this.getParanoiaLevelId(i);
      UUID id2 = o.getParanoiaLevelId(i);
      temp = id1.compareTo(id2);
      if(temp != 0)
      return temp;

      temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
      if(temp != 0)
      return temp;
      }

      // If you reach this point, I have no idea what you did to deserve this
      throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
      }

      }





      share|improve this answer




























        1












        1








        1







        While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".



        Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)



        import java.time.Instant;
        import java.util.ArrayList;
        import java.util.UUID;

        public class Test implements Comparable<Test>{

        private final UUID antiCollisionProp = UUID.randomUUID();
        private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();

        private UUID getParanoiaLevelId(int i) {
        while(antiuniverseProp.size() < i) {
        antiuniverseProp.add(UUID.randomUUID());
        }

        return antiuniverseProp.get(i);
        }

        @Override
        public int compareTo(Test o) {
        if(this == o)
        return 0;

        int temp = System.identityHashCode(this) - System.identityHashCode(o);
        if(temp != 0)
        return temp;

        //If the universe hates you
        temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
        if(temp != 0)
        return temp;

        //If the universe is activly out to get you
        temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
        if(temp != 0)
        return temp;

        for(int i = 0; i < Integer.MAX_VALUE; i++) {
        UUID id1 = this.getParanoiaLevelId(i);
        UUID id2 = o.getParanoiaLevelId(i);
        temp = id1.compareTo(id2);
        if(temp != 0)
        return temp;

        temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
        if(temp != 0)
        return temp;
        }

        // If you reach this point, I have no idea what you did to deserve this
        throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
        }

        }





        share|improve this answer















        While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".



        Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)



        import java.time.Instant;
        import java.util.ArrayList;
        import java.util.UUID;

        public class Test implements Comparable<Test>{

        private final UUID antiCollisionProp = UUID.randomUUID();
        private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();

        private UUID getParanoiaLevelId(int i) {
        while(antiuniverseProp.size() < i) {
        antiuniverseProp.add(UUID.randomUUID());
        }

        return antiuniverseProp.get(i);
        }

        @Override
        public int compareTo(Test o) {
        if(this == o)
        return 0;

        int temp = System.identityHashCode(this) - System.identityHashCode(o);
        if(temp != 0)
        return temp;

        //If the universe hates you
        temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
        if(temp != 0)
        return temp;

        //If the universe is activly out to get you
        temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
        if(temp != 0)
        return temp;

        for(int i = 0; i < Integer.MAX_VALUE; i++) {
        UUID id1 = this.getParanoiaLevelId(i);
        UUID id2 = o.getParanoiaLevelId(i);
        temp = id1.compareTo(id2);
        if(temp != 0)
        return temp;

        temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
        if(temp != 0)
        return temp;
        }

        // If you reach this point, I have no idea what you did to deserve this
        throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
        }

        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Apr 2 at 19:02

























        answered Apr 2 at 18:51









        TezraTezra

        5,23321244




        5,23321244























            0














            Assuming that with two objects with same name, if equals() returns false then compareTo() should not return 0. If this is what you want to do then following can help:




            • Override hashcode() and make sure it doesn't rely solely on name

            • Implement compareTo() as follows:


            public void compareTo(MyObject object) {
            this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
            }





            share|improve this answer
























            • Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

              – Balz Guenat
              Apr 1 at 8:22











            • That is the reason why I advised overriding hashcode() and make it rely not just on name.

              – Darshan Mehta
              Apr 1 at 8:26











            • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

              – Balz Guenat
              Apr 1 at 8:33
















            0














            Assuming that with two objects with same name, if equals() returns false then compareTo() should not return 0. If this is what you want to do then following can help:




            • Override hashcode() and make sure it doesn't rely solely on name

            • Implement compareTo() as follows:


            public void compareTo(MyObject object) {
            this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
            }





            share|improve this answer
























            • Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

              – Balz Guenat
              Apr 1 at 8:22











            • That is the reason why I advised overriding hashcode() and make it rely not just on name.

              – Darshan Mehta
              Apr 1 at 8:26











            • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

              – Balz Guenat
              Apr 1 at 8:33














            0












            0








            0







            Assuming that with two objects with same name, if equals() returns false then compareTo() should not return 0. If this is what you want to do then following can help:




            • Override hashcode() and make sure it doesn't rely solely on name

            • Implement compareTo() as follows:


            public void compareTo(MyObject object) {
            this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
            }





            share|improve this answer













            Assuming that with two objects with same name, if equals() returns false then compareTo() should not return 0. If this is what you want to do then following can help:




            • Override hashcode() and make sure it doesn't rely solely on name

            • Implement compareTo() as follows:


            public void compareTo(MyObject object) {
            this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
            }






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Apr 1 at 8:20









            Darshan MehtaDarshan Mehta

            23.6k32955




            23.6k32955













            • Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

              – Balz Guenat
              Apr 1 at 8:22











            • That is the reason why I advised overriding hashcode() and make it rely not just on name.

              – Darshan Mehta
              Apr 1 at 8:26











            • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

              – Balz Guenat
              Apr 1 at 8:33



















            • Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

              – Balz Guenat
              Apr 1 at 8:22











            • That is the reason why I advised overriding hashcode() and make it rely not just on name.

              – Darshan Mehta
              Apr 1 at 8:26











            • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

              – Balz Guenat
              Apr 1 at 8:33

















            Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

            – Balz Guenat
            Apr 1 at 8:22





            Object.hashCode has the same problem as System.identityHashCode in that in case of a collision, compareTo will return 0 for two different objects.

            – Balz Guenat
            Apr 1 at 8:22













            That is the reason why I advised overriding hashcode() and make it rely not just on name.

            – Darshan Mehta
            Apr 1 at 8:26





            That is the reason why I advised overriding hashcode() and make it rely not just on name.

            – Darshan Mehta
            Apr 1 at 8:26













            any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

            – Balz Guenat
            Apr 1 at 8:33





            any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

            – Balz Guenat
            Apr 1 at 8:33











            0














            You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.



            private static Set<Pair<C, C> collisions = ...;

            @Override
            public boolean equals(C other) {
            return this == other;
            }

            @Override
            public int compareTo(C other) {
            ...
            if (this == other) {
            return 0
            }
            if (super.equals(other)) {
            // Some stable order would be fine:
            // return either -1 or 1
            if (collisions.contains(new Pair(other, this)) {
            return 1;
            } else if (!collisions.contains(new Pair(this, other)) {
            collisions.add(new Par(this, other));
            }
            return 1;
            }
            ...
            }


            So go with the answer of Eran or put the requirement as such in question.




            • One might consider the overhead of non-identical 0 comparisons neglectable.

            • One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.






            share|improve this answer





















            • 1





              This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

              – Yakk - Adam Nevraumont
              Apr 1 at 15:44













            • @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

              – Joop Eggen
              Apr 1 at 15:55






            • 1





              Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

              – Voo
              Apr 1 at 16:31











            • @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

              – Tezra
              Apr 2 at 19:18











            • @Tezra "Made to work", agreed that the current solution is not going to be correct.

              – Voo
              Apr 2 at 19:27
















            0














            You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.



            private static Set<Pair<C, C> collisions = ...;

            @Override
            public boolean equals(C other) {
            return this == other;
            }

            @Override
            public int compareTo(C other) {
            ...
            if (this == other) {
            return 0
            }
            if (super.equals(other)) {
            // Some stable order would be fine:
            // return either -1 or 1
            if (collisions.contains(new Pair(other, this)) {
            return 1;
            } else if (!collisions.contains(new Pair(this, other)) {
            collisions.add(new Par(this, other));
            }
            return 1;
            }
            ...
            }


            So go with the answer of Eran or put the requirement as such in question.




            • One might consider the overhead of non-identical 0 comparisons neglectable.

            • One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.






            share|improve this answer





















            • 1





              This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

              – Yakk - Adam Nevraumont
              Apr 1 at 15:44













            • @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

              – Joop Eggen
              Apr 1 at 15:55






            • 1





              Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

              – Voo
              Apr 1 at 16:31











            • @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

              – Tezra
              Apr 2 at 19:18











            • @Tezra "Made to work", agreed that the current solution is not going to be correct.

              – Voo
              Apr 2 at 19:27














            0












            0








            0







            You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.



            private static Set<Pair<C, C> collisions = ...;

            @Override
            public boolean equals(C other) {
            return this == other;
            }

            @Override
            public int compareTo(C other) {
            ...
            if (this == other) {
            return 0
            }
            if (super.equals(other)) {
            // Some stable order would be fine:
            // return either -1 or 1
            if (collisions.contains(new Pair(other, this)) {
            return 1;
            } else if (!collisions.contains(new Pair(this, other)) {
            collisions.add(new Par(this, other));
            }
            return 1;
            }
            ...
            }


            So go with the answer of Eran or put the requirement as such in question.




            • One might consider the overhead of non-identical 0 comparisons neglectable.

            • One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.






            share|improve this answer















            You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.



            private static Set<Pair<C, C> collisions = ...;

            @Override
            public boolean equals(C other) {
            return this == other;
            }

            @Override
            public int compareTo(C other) {
            ...
            if (this == other) {
            return 0
            }
            if (super.equals(other)) {
            // Some stable order would be fine:
            // return either -1 or 1
            if (collisions.contains(new Pair(other, this)) {
            return 1;
            } else if (!collisions.contains(new Pair(this, other)) {
            collisions.add(new Par(this, other));
            }
            return 1;
            }
            ...
            }


            So go with the answer of Eran or put the requirement as such in question.




            • One might consider the overhead of non-identical 0 comparisons neglectable.

            • One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 1 at 15:55

























            answered Apr 1 at 8:40









            Joop EggenJoop Eggen

            78.9k755105




            78.9k755105








            • 1





              This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

              – Yakk - Adam Nevraumont
              Apr 1 at 15:44













            • @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

              – Joop Eggen
              Apr 1 at 15:55






            • 1





              Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

              – Voo
              Apr 1 at 16:31











            • @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

              – Tezra
              Apr 2 at 19:18











            • @Tezra "Made to work", agreed that the current solution is not going to be correct.

              – Voo
              Apr 2 at 19:27














            • 1





              This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

              – Yakk - Adam Nevraumont
              Apr 1 at 15:44













            • @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

              – Joop Eggen
              Apr 1 at 15:55






            • 1





              Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

              – Voo
              Apr 1 at 16:31











            • @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

              – Tezra
              Apr 2 at 19:18











            • @Tezra "Made to work", agreed that the current solution is not going to be correct.

              – Voo
              Apr 2 at 19:27








            1




            1





            This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

            – Yakk - Adam Nevraumont
            Apr 1 at 15:44







            This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.

            – Yakk - Adam Nevraumont
            Apr 1 at 15:44















            @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

            – Joop Eggen
            Apr 1 at 15:55





            @Yakk-AdamNevraumont true, just the mention of static should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?

            – Joop Eggen
            Apr 1 at 15:55




            1




            1





            Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

            – Voo
            Apr 1 at 16:31





            Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.

            – Voo
            Apr 1 at 16:31













            @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

            – Tezra
            Apr 2 at 19:18





            @Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P

            – Tezra
            Apr 2 at 19:18













            @Tezra "Made to work", agreed that the current solution is not going to be correct.

            – Voo
            Apr 2 at 19:27





            @Tezra "Made to work", agreed that the current solution is not going to be correct.

            – Voo
            Apr 2 at 19:27


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Færeyskur hestur Heimild | Tengill | Tilvísanir | LeiðsagnarvalRossið - síða um færeyska hrossið á færeyskuGott ár hjá færeyska hestinum

            He _____ here since 1970 . Answer needed [closed]What does “since he was so high” mean?Meaning of “catch birds for”?How do I ensure “since” takes the meaning I want?“Who cares here” meaningWhat does “right round toward” mean?the time tense (had now been detected)What does the phrase “ring around the roses” mean here?Correct usage of “visited upon”Meaning of “foiled rail sabotage bid”It was the third time I had gone to Rome or It is the third time I had been to Rome

            Bunad