[External] : Re: Future.resultNow / exceptionNow

Brian Goetz brian.goetz at oracle.com
Mon Nov 22 21:12:38 UTC 2021


> The implementation of a completion policy is spread across two places:
>
>  - the handler(s) passed to SE::fork
>  - the code following the call to SE::join

I'll add that it is harder to see this because the two policies we've 
specified -- have ad-hoc result states and APIs -- and also have methods 
that fuse state access with side effects.  (In other words, they're 
typical bespoke OO APIs.)  One could imagine a more functional approach, 
where all handlers had a more regularized API:

     interface Handler<S> {
         void accept(StructuredExecutor se, Future<?> task);

         S state();
     }

where S would be an algebraic data type (sum of products) representing 
the state.  Then we might define ShutdownOnFailure as implementing 
Handler<SOFStates> where:

     sealed interface SOFStates {
         record AllGood() extends SOFStates { }
         record GotException(Exception e) extends SOFStates { }
     }

then using it would look like:

     try (var executor = SE.open()) {
         var handler = new ShutdownOnFailure();

         // forking and joining

         switch (handler.state()) {
             case AllGood _ -> return Stream.of(future1, future2)...;
             case GotException(var e) -> throw new WAE(e);
        }
    }

I'm not suggesting that we do, or don't, redefine the handler API like 
this; I'm offering this as an explanation of why it might have been hard 
to see the relationship between the policy states and the code that 
follows the join.  By regularizing the policy states, we ask handler 
writers/users to engage in some more ceremony (declaring an ADT for 
their state), but regularizing their API and giving users a stronger 
nudge towards proper usage.



More information about the loom-dev mailing list