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, fo...@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.ma...@oracle.com>
To: "Remi Forax" <fo...@univ-mlv.fr>
Cc: "core-libs-dev" <core-libs-...@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