<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">This is an interesting issue, and it raises the question of how such issues are resolved.<div><br></div><div>My impression is that historically source code compatibility was given a high weight.</div><div>Is that not the case now?</div><div><br></div><div>Although the example may be carefully constructed, my understanding is that the problem</div><div>surfaced with programs that were not intentionally constructed to show this problem.</div><div><br></div><div>This issue is more general than the examples in your compatibility analysis report,</div><div>which I believe are limited to fixed sets of class names and method names.</div><div><br></div><div>Although you say that this issue does not represent a “bug” in type inference, I can’t help but</div><div>wonder whether a more flexible type system could handle this change without breaking</div><div>source compatibility.</div><div><br></div><div>If so, then a case could be made to delay the introduction of Sequenced Collections until the</div><div>type system can handle it without source incompatibility. Java has survived for many years</div><div>without Sequenced Collections. I don’t see a need to rush them out the door.</div><div><br></div><div>Being able to compatibly add new common supertypes would be valuable.</div><div><br></div><div>There are many other reasons for improving the type system. Of particular interest to me is</div><div>the mismatch between the current subtyping rules for parameterized types and the needs</div><div>of immutable collection types. (I understand that JDK did not go down this path, but</div><div>others have and will.)<br><div><br></div><div><br><div><br><blockquote type="cite"><div>On May 4, 2023, at 3:45 PM, Stuart Marks <stuart.marks@oracle.com> wrote:</div><br class="Apple-interchange-newline"><div>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<div><p>The introduction of Sequenced Collections in JDK 21+20 did make a
difference in this specific case. One can compile Rémi's example
on JDK 21+19 successfully, but it will fail on JDK 21+20.</p><p>Here's Rémi's example:</p><p><font face="monospace"> public static void
m(List<Supplier<? extends Map<String,
String>>> factories) {<br>
}<br>
<br>
public static void main(String[] args) {<br>
Supplier<LinkedHashMap<String,String>>
supplier1 = LinkedHashMap::new;<br>
Supplier<SortedMap<String,String>> supplier2
= TreeMap::new;<br>
var factories = List.of(supplier1, supplier2);<br>
m(factories);<br>
}</font><br>
</p><p>The type of 'factories' is inferred to be a List of the <i>something</i>
which is the common supertype (least upper bound, or LUB) of the
arguments. It's pretty easy to see this in an IDE or in jshell. In
JDK 21+19 factories is inferred to have this type:</p><p><font face="monospace"> List<Supplier<? extends
Map<String,String>>></font><br>
</p><p>whereas in JDK 21+20 it's inferred to have this type:</p><p><font face="monospace"> List<Supplier<? extends
SequencedMap<String,String>>></font></p><p>Rémi's example carefully defined the parameter of the m() method
so that it matches the first (and compiles successfully) but does
not match the second (and so fails with a compilation error).</p><p>This isn't a bug in type inference or in Sequenced Collections.
It's a consequence of a few phenomena: 1) the result of type
inference depends on the exact inputs given; 2) the result of type
inference depends on the current type hierarchy; 3) it's possible
to write source code that implicitly depends on a specific result
of type inference. Sequenced Collections changed the type
hierarchy, so inference gave different results, and the example
depended on getting a specific result under JDK 21+19.<br>
</p><p>When you changed the code to List.of(supplier1), this changed the
inputs to type inference, so it got a different result:<br>
</p><p><font face="monospace">
List<Supplier<LinkedHashMap<String,String>>></font><br>
</p><p>This doesn't match the parameter of the m() method, so this gives
a compilation error on all versions of the system.</p><p>As you observed, changing the declaration of m() to be:</p><p><font face="monospace"> public static void m(List<? extends
Supplier<? extends Map<String, String>>>
factories)</font><br>
</p><p>This lets the examples compile on JDK 21+19 and JDK 21+20,
whether List.of() is given one or both arguments. This change
broadens the set of types accepted by m(), reducing its specific
dependency on a specific arrangement of the type hierarchy. It's
also probably a good idea in general, as we recommend using
wildcard variance (? extends T) consistently in order to increase
the flexibility of methods. For example, I might have a MySupplier
functional interface that adds some features to the built-in
Supplier interface:</p><p><font face="monospace"> interface MySupplier<T> extends
Supplier<T> {<br>
// more features<br>
}</font><br>
</p><p>If the suppliers were declared as instances of MySupplier
instead, Rémi's example would fail even on JDK 21+19. So yes, in a
sense, this doesn't have much to do with the introduction of
Sequenced Collections.<br>
</p><p>s'marks<br>
</p><p><br>
</p><p><br>
</p>
<div class="moz-cite-prefix">On 5/2/23 5:09 AM, Blaise B. wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAEK75Eqq36wRodc=_n-6jsxAMJ2GTF-uPX-6DB2cVVWBTkPwSA@mail.gmail.com">
<div dir="ltr">
<div><br>
</div>
<div>Hello,<br>
<br>
I've tested the example provided by Rémi, and it looks like
the compile-time error has little to do with the integration
of Sequenced Collections into mainline.<br>
By changing the "factories" list to contain only one element
instead of two, the code does not compile even in previous jdk
versions (tested on jdk 17, 18, 19, 20, 21):<br>
<br>
import java.util.*;<br>
import java.util.function.Supplier;<br>
<br>
public class SequencedCollectionsTest {<br>
<br>
public static void m(List<Supplier<?
extends Map<String, String>>> factories) {<br>
}<br>
<br>
public static void main(String[] args) {<br>
Supplier<LinkedHashMap<String,String>> supplier1
= LinkedHashMap::new;<br>
Supplier<SortedMap<String,String>> supplier2 =
TreeMap::new;<br>
<br>
//var factories = List.of(supplier1,
supplier2);<br>
var factories = List.of(supplier1);<br>
<br>
m(factories);<br>
}<br>
}<br>
<br>
It all only compiles on all versions when I change the
signature of the method m() to:<br>
<br>
public static void m(List<? extends Supplier<?
extends Map<String, String>>> factories) {<br>
}<br>
<br>
So unless there are more other cases of failing compiles, it
seems to me like something was actually fixed in the latest
jdk21 build, and that the integration of Sequenced Collections
was just coincidence.<br>
<br>
Hope this helps.<br>
</div>
</div>
</blockquote>
</div>
</div></blockquote></div><br></div></div></body></html>