Example in support of CompletionHandler

Anthony Vanelverdinghe dev at anthonyv.be
Mon Nov 14 17:33:12 UTC 2022


(For a Markdown-rendered version, see: 
https://gist.github.com/anthonyvdotbe/7378020533aaced3fe4d19d3649bb98e )

While upgrading my Loom experiments to the current API, I noticed 
`CompletionHandler` has disappeared.

One of the experiments was to process a file by splitting it into blocks 
and processing each block in parallel.
To do so, I created a generic method which would do (1) the 
block-splitting, (2) map each block to a result, and (3) collect the 
results.
For (2) and (3) I'd pass in a functional interface as argument.

The method I had was something like:

```java
<T> void process(Path file, Function<ByteBuffer, T> mapper, 
CompletionHandler<? super T> collector) {
     try (var executor = StructuredExecutor.open()) {
         for(each block) {
             executor.fork(() -> mapper.apply(block), collector);
         }
         executor.join();
     }
}
```

And it would be used like:

```java
V result() {
     var collector = ...;
     process(file, mapper, collector);
     return collector.result();
}
```

To upgrade to the current API, the minimal change was:

```java
<T> void process(Path file, Function<ByteBuffer, T> mapper, 
StructuredTaskScope<? super T> scope) {
     try (scope) {
         for(each block) {
             scope.fork(() -> mapper.apply(block));
         }
         scope.join();
     }
}
```

While this works, it's ugly having to pass `StructuredTaskScope` 
instances around.
(Plus that the thread creating a `StructuredTaskScope` instance becomes 
its owner,
so in case the instance gets handed over to another thread while being 
passed around,
I guess this might result in unexpected behavior.)

So instead, I extended `StructuredTaskScope` to "bring back" the old API:

```java
final class Delegate<T> extends StructuredTaskScope<T> {

     interface CompletionHandler<U> {

         void handle(StructuredTaskScope<U> scope, Future<U> future);
     }

     private final CompletionHandler<T> handler;

     Delegate(CompletionHandler<T> handler) {
         this.handler = Objects.requireNonNull(handler);
     }

     @Override
     protected void handleComplete(Future<T> future) {
         Objects.requireNonNull(future);

         handler.handle(this, future);
     }
}
```

(I don't like that, unlike with the old API, both parameters of 
`CompletionHandler::handle` have a type argument now. It seems to 
indicate there's something unnatural going on.
And I tried to improve the generics with bounded wildcards, but all my 
attempts resulted in a compiler error for the `handler.handle(this, 
future);` invocation.)

This allowed me to write:

```java
<T> void process(Path file, Function<ByteBuffer, T> mapper, 
CompletionHandler<? super T> collector) {
     try (var scope = new Delegate<>(collector)) {
         for(each block) {
             scope.fork(() -> mapper.apply(block));
         }
         scope.join();
     }
}
```

This is better than passing the `StructuredTaskScope` around, but I'm 
not particularly fond of the `Delegate` class.

Another option would be to bring back `CompletionHandler`, but instead 
of it being a parameter of the `fork` method, make it a constructor 
parameter.
So then I'd be able to write:

```java
<T> void process(Path file, Function<ByteBuffer, T> mapper, 
CompletionHandler<? super T> collector) {
     try (var scope = new StructuredTaskScope<>(collector)) {
         for(each block) {
             executor.fork(() -> mapper.apply(block));
         }
         executor.join();
     }
}
```

To conclude: I believe the old API was a better fit for use cases like 
the above. (In case I missed an equally good solution with the new API, 
I'm all ears.)
Therefore I'd like to propose to do one of the following:
(a) bring back the old API
(b) bring back the old API, but move the `CompletionHandler` parameter 
from the `fork` method to the constructor

Or, if the above aren't an option:
(c) provide something like `Delegate` above, in addition to 
`ShutdownOn(Success|Failure)`

Kind regards,
Anthony



More information about the loom-dev mailing list