Re: The generic return type of result-less futures

Chris Povirk via Concurrency-interest <[email protected]> Tue, 14 Sep 2021 15:51:35 -0400
Newsgroups gmane.comp.java.jsr.166-concurrency
Message-ID <CAEvq2npNwvZoxHSRS0Uw7MhbBBap54QdN9_yC4GPeo-Va_Q_Sw@mail.gmail.com>
--===============9185328996080271749==
Content-Type: multipart/alternative; boundary="00000000000084d9ac05cbf9e95d"

--00000000000084d9ac05cbf9e95d
Content-Type: text/plain; charset="UTF-8"

I was in no way involved in any of these decisions, but I happen to have
opinions from designing similar APIs in Guava, which may or may not be of
any interest here.

First: It looks to me like the version of ExecutorService in which the
wildcard was "removed" was actually just the introduction of the new
`(Runnable, T)` overload, which naturally returns Future<T>? That is, I
think the wildcard-returning version has always been there?

Second: It looks like newer JDK methods have chosen to return Future<Void>.
For example, see CompletableFuture.allOf
<https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/concurrent/CompletableFuture.html#allOf(java.util.concurrent.CompletableFuture...)>
.

As for the actual considerations: There seems to be one main point in favor
of Future<?>:

   - "Future<?>" is shorter than "Future<Void>." It's also significantly
   shorter than "Future<@Nullable Void>," which is what you'd have to write
   when using some nullness checkers.

Future<Void> has various advantages:

   - It explicitly declares "no useful return type" rather than "possibly
   some useful return type, possibly not."
   - Wildcards are confusing: We saw a surprising number of callers who
   avoided submit(someRunnable) in favor of submit(someRunnable, null) just so
   that they could have a non-wildcard Future. They seemed to find it easier
   to reason about the types they'd need in their declarations when, e.g.,
   attaching a listener to the Future.
   - Wildcards are confusing: They lead to longer error messages.
   - Wildcards can cause type-inference problems: We've seen problems
   calling methods like Guava's Futures.whenAllComplete
   <https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/util/concurrent/Futures.html#whenAllComplete(com.google.common.util.concurrent.ListenableFuture...)>
   when passing Future instances whose value type is a wildcard.
   - While an API probably shouldn't require a Future<Void> as an input, if
   one does, then it's nice to have a Future<Void> available. (In contrast, an
   API that accepts a Future<?> works with a Future<Void> and a Future<?>
   equally well.)

Putting that all together, we picked Void for our new methods (example
<https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/util/concurrent/Futures.html#submit(java.lang.Runnable,java.util.concurrent.Executor)>
).

--00000000000084d9ac05cbf9e95d
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I was in no way involved in any of these decisions, but I =
happen to have opinions from designing similar APIs in Guava, which may or =
may not be of any interest here.<div><br></div><div>First: It looks to me l=
ike the version of ExecutorService in which the wildcard was &quot;removed&=
quot; was actually just the introduction of the new `(Runnable, T)` overloa=
d, which naturally returns Future&lt;T&gt;? That is, I think the wildcard-r=
eturning version has always been there?</div><div><br></div><div>Second: It=
 looks like newer JDK methods have chosen to return Future&lt;Void&gt;. For=
 example, see <a href=3D"https://docs.oracle.com/en/java/javase/16/docs/api=
/java.base/java/util/concurrent/CompletableFuture.html#allOf(java.util.conc=
urrent.CompletableFuture...)">CompletableFuture.allOf</a>.</div><div><br></=
div><div>As for the actual considerations: There seems to be one main point=
 in favor of Future&lt;?&gt;:</div><div><ul><li>&quot;Future&lt;?&gt;&quot;=
 is shorter than &quot;Future&lt;Void&gt;.&quot; It&#39;s also significantl=
y shorter than &quot;Future&lt;@Nullable Void&gt;,&quot; which is what you&=
#39;d have to write when using some nullness checkers.</li></ul><div>Future=
&lt;Void&gt; has various advantages:</div></div><div><ul><li>It explicitly =
declares &quot;no useful return type&quot; rather than &quot;possibly some =
useful return type, possibly not.&quot;</li><li>Wildcards are confusing: We=
 saw a surprising number of callers who avoided submit(someRunnable) in fav=
or of submit(someRunnable, null) just so that they could have a non-wildcar=
d Future. They seemed to find it easier to reason about the types they&#39;=
d need in their declarations when, e.g., attaching a listener to the Future=
.</li><li>Wildcards are confusing: They lead to longer error messages.=C2=
=A0<br></li><li>Wildcards can cause type-inference problems: We&#39;ve seen=
 problems calling methods like Guava&#39;s <a href=3D"https://guava.dev/rel=
eases/snapshot-jre/api/docs/com/google/common/util/concurrent/Futures.html#=
whenAllComplete(com.google.common.util.concurrent.ListenableFuture...)">Fut=
ures.whenAllComplete</a> when passing Future instances whose value type is =
a wildcard.</li><li>While an API probably shouldn&#39;t require a Future&lt=
;Void&gt; as an input, if one does, then it&#39;s nice to have a Future&lt;=
Void&gt; available. (In contrast, an API that accepts a Future&lt;?&gt; wor=
ks with a Future&lt;Void&gt; and a Future&lt;?&gt; equally well.)</li></ul>=
<div>Putting that all together, we picked Void for our new methods (<a href=
=3D"https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/util=
/concurrent/Futures.html#submit(java.lang.Runnable,java.util.concurrent.Exe=
cutor)">example</a>).</div></div></div>

--00000000000084d9ac05cbf9e95d--

--===============9185328996080271749==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

--===============9185328996080271749==--