The introduction of Sequenced collections is not a source compatible change

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Sat May 6 00:41:46 UTC 2023


Another way to help inference, in cases like this would be to break up 
the method chain - as follows:

final Stream<Collection<String>> stream = Stream.of(nestedDequeue, 
nestedList);
final List<Collection<String>> list = stream.toList();

In the above rewriting, now the target type Stream<Collection<String>> 
"drives" inference for Stream::of - meaning that inference will pick the 
"correct" supertype.

The problem with the original example is that the target type applies to 
the Stream::toList() call, and the call to Stream::of is type-checked in 
a bottom-up fashion, w/o any influence from the target-type.

This is, unfortunately, a known limitation of the inference scheme 
specified in the JLS and implemented by javac.

So, in a way, both the `var` example and this one are similar in spirit, 
as they both try to compute the least upper bound between two 
collections, in a situation where no target type is available: in one 
case, trivially, because the target is `var`; in the other case because 
the target doesn't "flow" to the method call that would require it the most.

Maurizio

On 04/05/2023 14:23, Raffaello Giulietti wrote:
> Without changing the semantics at all, you could also write
>
>     final List<Collection<String>> list = 
> Stream.<Collection<String>>of(nestedDequeue, nestedList).toList();
>
> to "help" type inference.
>
>
>
>
> On 2023-05-03 15:12, forax at univ-mlv.fr wrote:
>> Another example sent to me by a fellow French guy,
>>
>>      final Deque<String> nestedDequeue = new ArrayDeque<>();
>>      nestedDequeue.addFirst("C");
>>      nestedDequeue.addFirst("B");
>>      nestedDequeue.addFirst("A");
>>
>>      final List<String> nestedList = new ArrayList<>();
>>      nestedList.add("D");
>>      nestedList.add("E");
>>      nestedList.add("F");
>>
>>      final List<Collection<String>> list = Stream.of(nestedDequeue, 
>> nestedList).toList();
>>
>> This one is cool because no 'var' is involved and using 
>> collect(Collectors.toList()) instead of toList() solves the inference 
>> problem.
>>
>> Rémi
>>
>> ----- Original Message -----
>>> From: "Stuart Marks" <stuart.marks at oracle.com>
>>> To: "Remi Forax" <forax at univ-mlv.fr>
>>> Cc: "core-libs-dev" <core-libs-dev at openjdk.java.net>
>>> Sent: Tuesday, May 2, 2023 2:44:28 AM
>>> Subject: Re: The introduction of Sequenced collections is not a 
>>> source compatible change
>>
>>> Hi Rémi,
>>>
>>> Thanks for trying out the latest build!
>>>
>>> I'll make sure this gets mentioned in the release note for Sequenced
>>> Collections.
>>> We'll also raise this issue when we talk about this feature in the 
>>> Quality
>>> Outreach
>>> program.
>>>
>>> s'marks
>>>
>>> On 4/29/23 3:46 AM, Remi Forax wrote:
>>>> I've several repositories that now fails to compile with the latest 
>>>> jdk21, which
>>>> introduces sequence collections.
>>>>
>>>> The introduction of a common supertype to existing collections is 
>>>> *not* a source
>>>> compatible change because of type inference.
>>>>
>>>> Here is a simplified example:
>>>>
>>>>     public static void m(List<Supplier<? extends Map<String, 
>>>> String>>> factories) {
>>>>     }
>>>>
>>>>     public static void main(String[] args) {
>>>>       Supplier<LinkedHashMap<String,String>> supplier1 = 
>>>> LinkedHashMap::new;
>>>>       Supplier<SortedMap<String,String>> supplier2 = TreeMap::new;
>>>>       var factories = List.of(supplier1, supplier2);
>>>>       m(factories);
>>>>     }
>>>>
>>>>
>>>> This example compiles fine with Java 20 but report an error with 
>>>> Java 21:
>>>>     SequencedCollectionBug.java:28: error: method m in class 
>>>> SequencedCollectionBug
>>>>     cannot be applied to given types;
>>>>       m(factories);
>>>>       ^
>>>>     required: List<Supplier<? extends Map<String,String>>>
>>>>     found:    List<Supplier<? extends SequencedMap<String,String>>>
>>>>     reason: argument mismatch; List<Supplier<? extends 
>>>> SequencedMap<String,String>>>
>>>>     cannot be converted to List<Supplier<? extends 
>>>> Map<String,String>>>
>>>>
>>>>
>>>>
>>>> Apart from the example above, most of the failures I see are in the 
>>>> unit tests
>>>> provided to the students, because we are using a lot of 'var' in 
>>>> them so they
>>>> work whatever the name of the types chosen by the students.
>>>>
>>>> Discussing with a colleague, we also believe that this bug is not 
>>>> limited to
>>>> Java, existing Kotlin codes will also fail to compile due to this bug.
>>>>
>>>> Regards,
>>>> Rémi


More information about the core-libs-dev mailing list