<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Viktor Klang" <viktor.klang@oracle.com><br><b>To: </b>"Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"core-libs-dev" <core-libs-dev@openjdk.java.net><br><b>Sent: </b>Wednesday, January 17, 2024 9:00:32 PM<br><b>Subject: </b>Re: Gatherer API : wildcards complaint<br></blockquote></div><div><style style="display:none;"> P {margin-top:0;margin-bottom:0;} </style></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<div class="elementToProof"><span style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">Ah, now I see what you mean! Thank you \uD83D\uDC4D<br><br>
The reason for the signature of `Gatherer.of` was to mirror as much as possible of `Collector.of`[1] so I would argue that if we tweak the variance of one then we should consider tweaking it for both.<br><br></span></div>
<div class="elementToProof"><span style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">1:</span><span style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);"><a href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/stream/Collector.java#L264" id="LPlnk890719" target="_blank">https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/stream/Collector.java#L264</a></span><br data-mce-bogus="1"></div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
</div></blockquote><div><br></div><div>I agree.<br data-mce-bogus="1"></div><div>In terms of code, i suppose that we will need to add some unsafe cast because the Gatherer interface should not use wildcard (it will make the code that use the Gatherer awkward) but the factory methods should use wildcards.<br data-mce-bogus="1"></div><div>Those unsafe casts are safe because function parameter types are contravariant and return type covariant but there is no way to express than in the Java type system.<br></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);"><br>
</div>
<div id="Signature">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Cheers,<br>
√</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
</div></div></blockquote><div><br></div><div>Rémi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div id="Signature"><div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);"><br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b><br></b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b>Viktor Klang</b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Software Architect, Java Platform Group<br>
Oracle</div>
</div>
<hr style="display:inline-block;width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> forax@univ-mlv.fr <forax@univ-mlv.fr><br><b>Sent:</b> Wednesday, 17 January 2024 20:49<br><b>To:</b> Viktor Klang <viktor.klang@oracle.com><br><b>Cc:</b> core-libs-dev <core-libs-dev@openjdk.java.net><br><b>Subject:</b> [External] : Re: Gatherer API : wildcards complaint</font>
<div> </div>
</div>
<div>
<div style="font-family:arial,helvetica,sans-serif; font-size:12pt; color:#000000">
<div><br>
</div>
<div><br>
</div>
<hr id="x_zwchr">
<div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<b>From: </b>"Viktor Klang" <viktor.klang@oracle.com><br>
<b>To: </b>"Remi Forax" <forax@univ-mlv.fr>, "core-libs-dev" <core-libs-dev@openjdk.java.net><br>
<b>Sent: </b>Wednesday, January 17, 2024 5:49:01 PM<br>
<b>Subject: </b>Re: Gatherer API : wildcards complaint<br>
</blockquote>
</div>
<div><style style="display:none">
<!--
p
{margin-top:0;
margin-bottom:0}
-->
</style></div>
<div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div><span style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:#000000">Hi
Rémi,</span></div>
<div class="x_elementToProof"><span style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:#000000"><br></span></div>
<div class="x_elementToProof"><span style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:#000000">Thank
you for the feedback—examples would be </span><span style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:#000000">much
appreciated!</span></div>
</blockquote>
<div><br>
</div>
<div>Here is an example with an interface and a class,</div>
<div><br>
</div>
<div>
<div style="background-color:#ffffff; color:#080808">
<pre style="font-family:'JetBrains Mono',monospace; font-size:9.8pt"><span style="color:#0033b3">interface </span><span style="color:#000000">Counter </span>{<br> <span style="color:#0033b3">void </span><span style="color:#00627a">increment</span>();<br> <span style="color:#0033b3">int </span><span style="color:#00627a">value</span>();<br>}<br><br><span style="color:#000000">Gatherer</span><<span style="color:#000000">String</span>, <span style="color:#000000">Counter</span>, <span style="color:#000000">Integer</span>> <span style="color:#00627a">count</span>() {<br> <span style="color:#0033b3">class </span><span style="color:#000000">CounterImpl </span><span style="color:#0033b3">implements </span><span style="color:#000000">Counter </span>{<br> <span style="color:#0033b3">int </span><span style="color:#871094">counter</span>;<br><br> <span style="color:#9e880d">@Override<br></span><span style="color:#0033b3">public void </span><span style="color:#00627a">increment</span>() {<br> <span style="color:#871094">counter</span>++;<br> }<br><br> <span style="color:#9e880d">@Override<br></span><span style="color:#0033b3">public int </span><span style="color:#00627a">value</span>() {<br> <span style="color:#0033b3">return </span><span style="color:#871094">counter</span>;<br> }<br> }<br> <span style="color:#000000">Supplier</span><<span style="color:#000000">CounterImpl</span>> <span style="color:#000000">initializer </span>= <span style="color:#000000">CounterImpl</span>::<span style="color:#0033b3">new</span>;<br> <span style="color:#000000">Gatherer</span>.<span style="color:#000000">Integrator</span><<span style="color:#000000">Counter</span>, <span style="color:#000000">String</span>, <span style="color:#000000">Gatherer</span>.<span style="color:#000000">Downstream</span><? <span style="color:#0033b3">super </span><span style="color:#000000">Integer</span>>> <span style="color:#000000">integrator </span>= (<span style="color:#000000">counter</span>, <span style="color:#000000">_</span>, <span style="color:#000000">_</span>) -> {<br> <span style="color:#000000">counter</span>.increment();<br> <span style="color:#0033b3">return true</span>;<br> };<br> <span style="color:#000000">BiConsumer</span><<span style="color:#000000">Counter</span>, <span style="color:#000000">Gatherer</span>.<span style="color:#000000">Downstream</span><? <span style="color:#0033b3">super </span><span style="color:#000000">Integer</span>>> <span style="color:#000000">finisher </span>= (<span style="color:#000000">counter</span>, <span style="color:#000000">downstream</span>) -> {<br> <span style="color:#000000">downstream</span>.push(<span style="color:#000000">counter</span>.value());<br> };<br> <span style="color:#0033b3">return </span><span style="color:#000000">Gatherer</span>.<span style="font-style:italic">ofSequential</span>(<span style="color:#000000">initializer</span>, <span style="color:#000000">integrator</span>, <span style="color:#000000">finisher</span>); <span style="color:#8c8c8c; font-style:italic">// does not compile :(</span><br>}<br><br><span style="color:#0033b3">void </span><span style="color:#00627a">main</span>() {<br><span style="color:#000000"> System</span>.<span style="color:#871094; font-style:italic">out</span>.println(<span style="color:#000000">Stream</span>.<span style="font-style:italic">of</span>(<span style="color:#067d17">"foo"</span>).gather(count()).findFirst().orElseThrow());<br>}</pre>
</div>
</div>
<div><br>
</div>
<div>if instead of explicitly typing each functions, we directly call ofSequential, it works</div>
<div><br>
</div>
<div>
<div style="background-color:#ffffff; color:#080808">
<pre style="font-family:'JetBrains Mono',monospace; font-size:9.8pt"><span style="color:#0033b3">return </span><span style="color:#000000">Gatherer</span>.<span style="font-style:italic">ofSequential</span>(<br> <span style="color:#000000">CounterImpl</span>::<span style="color:#0033b3">new</span>,<br> (<span style="color:#000000">Counter counter</span>, <span style="color:#000000">String _</span>, <span style="color:#000000">Gatherer</span>.<span style="color:#000000">Downstream</span><? <span style="color:#0033b3">super </span><span style="color:#000000">Integer</span>> <span style="color:#000000">_</span>) -> {<br> <span style="color:#000000">counter</span>.increment();<br> <span style="color:#0033b3">return true</span>;<br> },<br> (<span style="color:#000000">Counter counter</span>, <span style="color:#000000">Gatherer</span>.<span style="color:#000000">Downstream</span><? <span style="color:#0033b3">super </span><span style="color:#000000">Integer</span>> <span style="color:#000000">downstream</span>) -> {<br> <span style="color:#000000">downstream</span>.push(<span style="color:#000000">counter</span>.value());<br> }<br>);</pre>
</div>
</div>
<div><br>
</div>
<div>because here, CounterImpl::new is inferred as Supplier<Counter>.<br>
</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:#000000">
<br>
</div>
<div id="x_Signature">
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:#000000">
Cheers,<br>
√</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:#000000">
<br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:#000000">
<b><br></b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:#000000">
<b>Viktor Klang</b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:#000000">
Software Architect, Java Platform Group<br>
Oracle</div>
</div>
<hr style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><span style="font-size:11pt; color:#000000; font-family:Calibri,sans-serif"><b>From:</b> core-libs-dev <core-libs-dev-retn@openjdk.org> on
behalf of Remi Forax <forax@univ-mlv.fr><br><b>Sent:</b> Wednesday, 17 January 2024 16:55<br><b>To:</b> core-libs-dev <core-libs-dev@openjdk.java.net><br><b>Subject:</b> Gatherer API : wildcards complaint</span>
<div> </div>
</div>
<div class="x_BodyFragment">
<div class="x_PlainText">Hello,<br>
this is a minor complaint but I do not see a raison to not getting this right.<br>
<br>
Currently the Gatherer API does not use the wildcard correctly, which is not fully an issue because there is "enough" wildcards that if you rely on the inference, it will work.<br>
<br>
The problem is that when you write code, you make mistakes and usually when you have a typing issue, a way to debug it is to fix the type arguments de-activating the inference.<br>
But because there are some missing wildcards, this debugging strategy just fail flat with more typing errors.<br>
<br>
I think that fixing the missing wildcards will hep users (or a least me) to have a better experience when using the Gatherer API.<br>
<br>
I can help and propose a PR if you want.<br>
<br>
regards,<br>
Rémi<br>
</div>
</div>
<br>
</blockquote>
</div>
</div>
</div><br></blockquote></div></div></body></html>