<div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hey Alan,<br><br>> I assume you mean allUntil(Predicate)<br><br>Whoops, yes.<br><br>> With allUntil then it does mean that the<br>> predicate may not be pure function<br><br>Mine was. It was basically just a Joiner.allUntil(t -> t.state() == FAILED && t.exception() instanceof SomeException).</div><div class="gmail_default" style="font-family:monospace">
<div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Side
 note -- excited to see what Pattern-matching will bring to the Subtask 
type specifically. Deconstructing it is something I will be doing a lot 
of.<br></div>

<br></div><div class="gmail_default" style="font-family:monospace">But yes, if you are referring to once the allUntil became insufficient for my needs, then yeah. I didn't like the idea of implementing multiple levels of joiners, all with their own state. I could certainly make it work, but that was my point with saying "bad memories" -- I remember how much work it was making it work with inheritance in the past for separate contexts. And I don't want to relive those bad memories. In general, I try to avoid too many levels of inheritance with state.</div><div class="gmail_default" style="font-family:monospace"><br>> One thing that would help is if your<br>> could enumerate a few of the Joiners<br>> that you implemented. I'm wondering<br>> if they are general purpose of very<br>> specific.<br><br>Sure. Let me highlight 5 of them. Let me know if you need more examples -- I have about 30+ custom implementations.<br><br>1. A stateful Joiner<T, Optional<R>> that folds each success into an add() on a builder for <R>. When add() returns false (has sufficient input), the joiner cancels the scope. It returns an Optional of the constructed data model.<br><br>2. A stateful Joiner<T, Stream<Subtask<T>>> that cancels the scope once I hit X number of tasks that throw SomeException. It returns the tasks that succeeded, plus those X failures.<br><br>3. A stateful Joiner<T, Optional<R>> that takes each successful result, performs an RPC call using that result, then cancels the scope if the rpc call is successful. It returns an Optional of the first successful rpc call.<br><br>4. A stateful Joiner<List<T>, Optional<R>> that, upon each successful List<T>, recursively creates new scopes inside of the onComplete, with the exit condition being that a list is empty. It then performs a reduce on the returned scopes, bubbling up the call stack until it returns an Optional<R><br><br>5. A stateful Joiner<T, Optional<T>> that cancels the scope on the first success, but uses a Predicate<T> to determine a success. It returns an Optional of the result.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Let me know if there is anything further that I can provide.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Aug 16, 2025 at 4:53 AM Alan Bateman <<a href="mailto:alan.bateman@oracle.com" target="_blank">alan.bateman@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 15/08/2025 19:44, David Alayachew wrote:<br>
> :<br>
><br>
> So, when someone recently challenged me to use Joiners (rather than <br>
> the old STS preview versions I was used to), I started creating <br>
> Joiners to handle all sorts of failure and outcomes. At first, a lot <br>
> of them could be handled by the Joiner.awaitUntil(), where I would <br>
> just check and see if the task failed, then handle the error. But as I <br>
> got further and further along, I started needing to add state to my <br>
> Joiners in order to get the failure handling that I wanted. For <br>
> example, if a certain number of timeouts occur, cancel the scope. <br>
> Well, that necessitates an AtomicNumber.<br>
><br>
I assume you mean allUntil(Predicate), which is intended to make it easy <br>
to create a Joiner that implements a cancellation policy. Joiners are <br>
inherently stateful as many will accumulate results or exceptions, or <br>
maybe just count failures.  With allUntil then it does mean that the <br>
predicate may not be pure function, is that the reason for the <br>
hesitation? Beyond allUntil does mean implementing the Joiner interface. <br>
I think your mails are pondering whether there is something between <br>
allUntil and implementing Joiner yourself. I don't think we've had <br>
enough feedback to date to know if there is something needed there. One <br>
thing that would help is if your could enumerate a few of the Joiners <br>
that you implemented. I'm wondering if they are general purpose of very <br>
specific.<br>
<br>
-Alan<br>
</blockquote></div>