Comparator.reversed() type inference issue

Remi Forax forax at univ-mlv.fr
Tue Jun 9 08:25:10 UTC 2020


----- Mail original -----
> De: "Tagir Valeev" <amaembo at gmail.com>
> À: "Attila Szegedi" <szegedia at gmail.com>
> Cc: "core-libs-dev" <core-libs-dev at openjdk.java.net>
> Envoyé: Mardi 9 Juin 2020 09:05:42
> Objet: Re: Comparator.reversed() type inference issue

> Hello!
> 
> This is more related to Java language specification and implementation
> than to core libraries, so compiler-dev is a more relevant mailing
> list. The current behavior perfectly follows the specification (JLS,
> 15.12):
> 
> A method invocation expression is a poly expression if all of the
> following are true:
> - The invocation appears in an assignment context or an invocation
> context (§5.2, §5.3). (1)
> - If the invocation is qualified (that is, any form of
> MethodInvocation except for the first), then the invocation elides
> TypeArguments to the left of the Identifier. (2)
> - The method to be invoked, as determined by the following
> subsections, is generic (§8.4.4) and has a return type that mentions
> at least one of the method's type parameters. (3)
> 
> If method invocation is a qualifier (in your case
> Map.Entry.comparingByValue() is a qualifier of reversed() call) then
> the context is neither assignment, nor invocation, hence (1) is not
> satisfied, hence it's a standalone expression, hence its type is
> determined solely by expression content. That's why to determine the
> type of Map.Entry.comparingByValue() we cannot look outside and must
> consider only the expression content. So its type is determined to be
> Comparator<Entry<Object,V#2>> (V#2 extends Comparable<? super V#2>),
> as we don't have any other information. The reversed() call is also
> standalone, as the reversed() method is not generic, so (3) is not
> satisfied. Thus its type is just the same as its qualifier type.
> 
> People asked many times whether it's possible to make this code
> working without explicit type arguments. However, it's not just a
> trivial patch to the compiler and the spec. It's huge amount of work
> that may introduce tons of bugs, compiler crashes (I would expect
> StackOverflowError appear often during the compilation), compiler
> performance regression, and so on. Also, loads of inconsistencies
> between compiler and IDE behavior. I personally don't work on Java
> compiler, but I sometimes investigate bugs inside the IntelliJ IDEA
> type inference procedure. Believe me, it's already insanely complex,
> and the fact that at very least we can exclude qualifiers from the
> equation is really relieving. So while I cannot say for the whole
> OpenJDK team, I hardly believe this could be implemented any time
> soon.

I don't see how you can fix it even with a lot of dust of magic stars,
you have only the type information of the return value of
  Map.Entry.comparingByValue().reversed()

but they can no travel backward to Map.Entry.comparingByValue() because you have no idea of the return type of Map.Entry.comparingByValue() so you don't know the class that contains the method "reversed".

> 
> With best regards,
> Tagir Valeev.

Rémi

> 
> On Sun, Jun 7, 2020 at 7:34 PM Attila Szegedi <szegedia at gmail.com> wrote:
>>
>> Hi folks,
>>
>> I'm teaching Java lately, and while teaching streams I use that good old
>> chestnut, the word count example. I'm baffled with some type inference woes,
>> though… trying to specify a reverse comparator using Comparator.reversed()
>> makes javac sad, e.g. this does not compile[1]:
>>
>>        Map<String, Long> x = someMap();
>>
>>        var rs1 = x.entrySet().stream().sorted(
>>            Map.Entry.comparingByValue().reversed()
>>        );
>>
>> On the other hand, using Collections.reverseOrder does compile:
>>
>>        var rs2 = x.entrySet().stream().sorted(
>>            Collections.reverseOrder(
>>                Map.Entry.comparingByValue()
>>            )
>>        );
>>
>> Happens on both Java 11 and 14. It’s just baffling because based on type
>> signatures, it seems reasonable the first form should work as well.
>>
>> Thanks for any enlightenment!
>>
>> Attila.
>>
>> ---
>> [1] -Xdiags:verbose on Java 14 says:
>> error: no suitable method found for sorted(Comparator<Entry<Object,V#1>>)
>>        var rs1 = x.entrySet().stream().sorted(
>>
>>    method Stream.sorted() is not applicable
>>      (actual and formal argument lists differ in length)
>>    method Stream.sorted(Comparator<? super Entry<String,Long>>) is not applicable
>>      (argument mismatch; Comparator<Entry<Object,V#2>> cannot be converted to
>>      Comparator<? super Entry<String,Long>>)
>>  where V#1,V#2 are type-variables:
>>    V#1 extends Comparable<? super V#1>
> >    V#2 extends Comparable<? super V#2>


More information about the core-libs-dev mailing list