RFR: 8199318: add idempotent copy operation for Map.Entry
forax at univ-mlv.fr
forax at univ-mlv.fr
Thu Jun 3 21:49:40 UTC 2021
> De: "John Rose" <john.r.rose at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Peter Levart" <peter.levart at gmail.com>, "Rémi Forax"
> <forax at openjdk.java.net>, "core-libs-dev" <core-libs-dev at openjdk.java.net>
> Envoyé: Jeudi 3 Juin 2021 22:51:28
> Objet: Re: RFR: 8199318: add idempotent copy operation for Map.Entry
> On Jun 3, 2021, at 12:46 PM, Remi Forax < [ mailto:forax at univ-mlv.fr |
> forax at univ-mlv.fr ] > wrote:
>> I kind of regret that the compiler does not provide automatically an
>> implementation of compareTo if the record implements Comparable.
>> People sucks at writing compareTo and the resulting bugs are hard to
>> find/reproduce.
> That’s a slippery slope. IIRC we consciously stopped
> before that step.
> That said, there are other ways to fix this. We should
> have utilities (maybe in the JDK but not the JLS) which
> build such methods and make it easy for users to grab onto
> them. Maybe something like this:
> interface ComparableRecord<T extends Record & ComparableRecord<T>>
> extends Comparable<T> { … }
> record Foo(int x, String y) implements ComparableRecord<Foo> { … }
> [ http://cr.openjdk.java.net/~jrose/draft/ComparableRecord.java |
> http://cr.openjdk.java.net/~jrose/draft/ComparableRecord.java ]
The main issue with this kind of code is that the JIT does not see through the ClassValue.
Tweaking a little bit your code, I get
(It's a PITA that we have to use a raw type to workaround circularly defined parameter type)
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
@SuppressWarnings({"rawtypes","unchecked"})
interface ComparableRecord<T extends Record & ComparableRecord<T>> extends Comparable<T> {
@Override default int compareTo(T that) {
if (this.getClass() != that.getClass()) {
throw new IllegalArgumentException("not same class");
}
return COMPARE_TO_METHODS.get(this.getClass()).compare(this, that);
}
static final ClassValue<Comparator<Object>> COMPARE_TO_METHODS = new ClassValue<>() {
@Override
protected Comparator<Object> computeValue(Class<?> type) {
return Stream.of(type.getRecordComponents())
.map(component -> {
var accessor = component.getAccessor();
return Comparator.<Object, Comparable>comparing(r -> {
try {
return (Comparable<?>) accessor.invoke(r);
} catch (ReflectiveOperationException ex) {
throw new IllegalArgumentException(ex);
}
});
})
.reduce((r1, r2) -> 0, Comparator::thenComparing, (_1, _2) -> { throw null; });
}
};
static void main(String[] args) {
record Foo(int x, String y) implements ComparableRecord<Foo> { }
var list = Stream.of(new Foo(2, "foo"), new Foo(2, "bar")) .sorted().toList();
System.out.println(list);
}
}
> — John
More information about the core-libs-dev
mailing list