The introduction of Sequenced collections is not a source compatible change

Jens Lideström jens at lidestrom.se
Fri May 5 09:15:26 UTC 2023


I want contribute an observation of a tangential fact about this example. This might be interesting reminder in a discussion of the tricky parts of type inference.


### The fact

The reason that this example does not compile with Sequenced collections is a limitation in the type inference algorithm:

Type constraints that are inferred from instance method calls do not influence inference of types in the receiver type expression.

### In the given example

1. `List<Collection<String>> list =` is the target type of `.toList()` so this could influence inference of its type parameters.

2. But the inferred type parameters of `.toList()` does not influence the inference of types for its receiver expression, `Stream.of(nestedDequeue, nestedList)`.

If not for this fact the type of `Stream.of(nestedDequeue, nestedList)` could be inferred to be `Stream<Collection>`, but with the current algorithm it will be inferred to be `Stream<SequencedCollection>`, leading to the source incompatibility.

Static method calls don't have this limitation. This is a bit weird, because instance method mostly act like static method, but with an implicit receiver argument. I don't know if there are any strong technical reasons to why there is a difference here.

Using a static `toList` method the given example looks like this, and type checks also with Sequenced collections:

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

public static <T> List<T> toList(Stream<T> s) {
     return s.toList();
}
```

(One can change the type of `list` to `List<Iterable<String>>` to experiment with this even without Sequenced collections`.)

It would be interesting to have a discussion about whether this limitation could be overcome at some other time.

Regards,
Jens Lideström

PS: Type inference algorithms are soooo much fun, aren't they?


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