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 "removed&= quot; was actually just the introduction of the new `(Runnable, T)` overloa= d, which naturally returns Future<T>? 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<Void>. 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<?>:</div><div><ul><li>"Future<?>"= is shorter than "Future<Void>." It's also significantl= y shorter than "Future<@Nullable Void>," which is what you&= #39;d have to write when using some nullness checkers.</li></ul><div>Future= <Void> has various advantages:</div></div><div><ul><li>It explicitly = declares "no useful return type" rather than "possibly some = useful return type, possibly not."</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'= 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've seen= problems calling methods like Guava'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'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<?> wor= ks with a Future<Void> and a Future<?> 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==--