compareTo and deriving

Brian Goetz brian.goetz at oracle.com
Tue Dec 5 15:17:32 UTC 2017


At some level, this goes to the heart of "why should records, and not 
tuples, be our 'plain data' abstraction."  Adding behavior to a record, 
**where that behavior is derived strictly from the state**, is easy and 
natural.

You can look at the "but I have to write compareTo" issue as glass 90% 
full or 10% empty; a record starts life with a sensible ctor, dtor, 
accessors, equals, hashCode, and toString.  So adding compareTo is 
pretty easy.  Note also that there's no way we can reasonably derive 
compareTo from the state description, since (a) not all state fields are 
going to be relevant for ordering comparison and (b) the order in which 
they are declared may not be the natural comparison order.  So somewhere 
in the program the user is going to have to write down that "a Person is 
compared by (lastName, firstName)", somehow.

We could of course invent all sorts of shorthands, but I think the 
return-on-complexity there is limited, as the natural way to say this is 
pretty straightforward:

     record Person(String first, String last, String age)
             implements Comparable<Person> {

         private static final Comparator<Person> cc
             = 
Comparators.comparing(Person::last).thenComparing(Person::first);

         public int compareTo(Person other) {
             return cc.compareTo(other);
         }
     }

But, let's not get distracted by Billy, we care about semantics. Where 
are the pitfalls you see of this approach where it might run afoul of 
the "consistency between equals and compareTo is recommended" dictum?


On 12/5/2017 3:12 AM, forax at univ-mlv.fr wrote:
> So let restart by trying to untangle things.
>
> First question, should we only support Object methods (toString, equals, hashCode) or more, again here, two sub questions,
> it can be only (toString, equals, hashCode) in the first release and more in a subsequent release.
> Why more, the question is where to put the bar, if we do only toString, equals, hashCode, people will ask for compareTo (i don't think there is another method than compareTo but i may be wrong). The rational to introduce compareTo is that the semantics of compareTo is linked to the semantics of equals which is generated, so asking someone to write compareTo given that he doesn't have to write equals is clunky. There are several reason to not introduce compareTo. toString, equals, hashCode cover most of the case and we have to stop somewhere, people tend to use compareTo at a place where they should use a Comparator, i.e. the order defined by compareTo is not a 'natural' order.
>
> Second question, how to specify the mapping between toString, equals, hashCode and their implementation ? Should we have a way to extends the mapping if we want to introduce compareTo later without having to change the JLS. Again, sub-questions, Should this mapping being explicit like in Haskell with deriving or should it be implicit, there is no real need to specify a mapping for the method for j.l.Object because those method declaration are already present, and if the record implements Comparable it means that we have to provide the implementation of compareTo.
>
> regards,
> Rémi
>
> ----- Mail original -----
>> De: forax at univ-mlv.fr
>> À: "Brian Goetz" <brian.goetz at oracle.com>
>> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>> Envoyé: Lundi 4 Décembre 2017 16:12:58
>> Objet: Re: compareTo and deriving
>> ----- Mail original -----
>>> De: "Brian Goetz" <brian.goetz at oracle.com>
>>> À: "Remi Forax" <forax at univ-mlv.fr>, "amber-spec-experts"
>>> <amber-spec-experts at openjdk.java.net>
>>> Envoyé: Lundi 4 Décembre 2017 15:54:13
>>> Objet: Re: compareTo and deriving
>>> As you might remember from the EG meeting, we have toyed with a notion
>>> of "method builders" which would be a more declarative way to declare
>>> template-izable methods.  The intent all along was that, once we have
>>> such a mechanism, records would just be a consumer of such a mechanism.
>>>
>>> That said, such a mechanism is bigger both from a technical perspective
>>> and a bikeshed perspective.  90% of the current OO-ceremony-pain is in
>>> ctors, Object methods, and accessors.  So my preference would be to nail
>>> down the semantics of data classes first, and then explore whether it
>>> makes sense to surface a more general mechanism.
>> I'm trying to propose a middle ground (not too far from only support Object
>> methods) to allow to not have too much couple between the JLS and the
>> metafactory methods.
>>
>> One advantage i see to have compareTo generated is that most implementation i
>> see of the compareTo are broken either because of the primitive overflowing or
>> compareTo and equals not having compatible semantics. One problem we will have
>> if we let people to write compareTo is that it will be harder to get it right
>> because equals will be generated while compareTo will be written manually
>> without seeing the code of equals.
>>
>> Rémi
>>
>>>
>>> On 12/4/2017 8:34 AM, Remi Forax wrote:
>>>> Ok,
>>>> record/data class currently provides getters and toString/equals/hashCode, what
>>>> if i want to add a compareTo.
>>>>
>>>> In Haskell, it's easy, one can use 'deriving', in Java, it can be written that
>>>> way,
>>>>     record Point(int x, int y) implements Comparable<Point>
>>>>       deriving equals, hashCode, toString, compareTo;
>>>>
>>>> For the compiler, the method exists in the supertypes, so the signature of the
>>>> method can be computed from the super types,
>>>> after each generated method use an invokedynamic with the same meta protocol (a
>>>> list of getters),
>>>> so if by convention "equals", "hashCode", "toString", "compareTo" are the names
>>>> of some bootstrap methods in a class DerivingMetaFactory,
>>>> it can be trivial for a JDK developer to add a new bootstrap method without
>>>> having to change the JLS.
>>>>
>>>> So my point is, that we can specify once how the compiler should generate codes
>>>> for any generated methods in an extensible way.
>>>>
>>>> regards,
>>>> Rémi



More information about the amber-spec-experts mailing list