Oh, I'm already doing that. Lol, I love STS BECAUSE nesting scopes is so easy to do.
But that's an interesting idea. I kind of see what you mean -- maybe I am stuffing too much logic into a single Joiner. I can't tell yet, so I guess I'll just have to try it out and get back to you. Thanks for the tip. On Fri, Aug 15, 2025, 5:09 PM Viktor Klang <viktor.kl...@oracle.com> wrote: > Hi David, > > Thanks for the added detail, that really helps my understanding of your > situation. > > Did you try/consider/evaluate nested scopes (each with different Joiner > strategies) over composing Joiners themselves? > And if you did, what were your findings when comparing those two different > approaches? > > Cheers, > √ > > > *Viktor Klang* > Software Architect, Java Platform Group > Oracle > ------------------------------ > *From:* David Alayachew <davidalayac...@gmail.com> > *Sent:* Friday, 15 August 2025 20:53 > *To:* Viktor Klang <viktor.kl...@oracle.com> > *Cc:* loom-dev <loom-dev@openjdk.org> > *Subject:* [External] : Re: My experience with Structured Concurrency > > One other detail I'd like to highlight. > > Much like Collectors and Gatherers, there are a handful of super useful > ones that you use everywhere, and then the rest are ad-hoc, inline ones > where you sort of just make your own to handle a custom scenario. If you > use streams often, you will run into those frequently, and that's why those > factory methods are fantastic. > > Well, I have kind of found myself in the same position for Joiners. > Joiners aren't as complex as Collectors and Gatherers, so there has > certainly been less need for it. But I am also only a few weeks into using > Joiners (though, I used STS for over a year). If I feel this strain now, > then I feel like this experience is definitely worth sharing. > > On Fri, Aug 15, 2025, 2:44 PM David Alayachew <davidalayac...@gmail.com> > wrote: > > Sure. > > Long story short, the biggest reason why STS is so useful for me is > because it allows me to fire off a bunch of requests, and handle their > failures and outcomes centrally. That is the single most useful feature of > this library for me. It's also why Future.status was not so useful for me > -- it calls get under the hood, and therefore might fail! Handling that was > too much scaffolding. > > So, when someone recently challenged me to use Joiners (rather than the > old STS preview versions I was used to), I started creating Joiners to > handle all sorts of failure and outcomes. At first, a lot of them could be > handled by the Joiner.awaitUntil(), where I would just check and see if the > task failed, then handle the error. But as I got further and further along, > I started needing to add state to my Joiners in order to get the failure > handling that I wanted. For example, if a certain number of timeouts occur, > cancel the scope. Well, that necessitates an AtomicNumber. > > Then, as the error-handling got more and more complex, I started finding > myself making a whole bunch of copy paste, minor variations of similar > Joiners. Which isn't bad or wrong, but started to feel some strain. Now, I > need to jump through an inheritance chain just to see what my Joiner is > really doing. It wasn't so bad, but I did start to feel a little uneasy. > Bad memories. > > So, the solution to a problem like this is to create a Joiner factory. > Which is essentially what I started to write before I started remembering > how Collectors and Gatherers worked. At that point, I kind of realized that > this is worth suggesting, which prompted me to write my original email. > > Like I said, not a big deal if you don't give it to me -- I can just make > my own. > > But yes, that is the surrounding context behind that quote. Let me know if > you need more details. > > > On Fri, Aug 15, 2025, 9:25 AM Viktor Klang <viktor.kl...@oracle.com> > wrote: > > Hi David, > > First of all—thank you for your feedback! > > I'm curious to learn more about why you ended up in the situation you > describe below, specifically about what use-cases led you into wishing for > an augmentation to Joiner to facilitate composition. > > Are you able to share more details? > > >Which, funnily enough, led to a slightly different problem -- I found > myself wanting an easier way to create Joiners. Since I was leaning on > Joiners so much more heavily than I was for STS, I ended up creating many > Joiners that do almost the same thing, with just minor variations. And > inheritance wasn't always the right answer, as I can't inherit from > multiple classes. Plus, most of my joiners were stateful, but I only wanted > the non-stateful parts of it. I could do composition, but it sort of felt > weird to delegate to multiple other Joiners. > > Cheers, > √ > > > *Viktor Klang* > Software Architect, Java Platform Group > Oracle > ------------------------------ > *From:* loom-dev <loom-dev-r...@openjdk.org> on behalf of David Alayachew > <davidalayac...@gmail.com> > *Sent:* Friday, 15 August 2025 11:52 > *To:* loom-dev <loom-dev@openjdk.org> > *Subject:* My experience with Structured Concurrency > > Hello @loom-dev <loom-dev@openjdk.org>, > > I just wanted to share my experience with Structured Concurrency. I had > actually been using it for a while now, but only recently got experience > with the new Joiner. After trying it out, my previously stated opinion has > changed. > > Overall, Structured Concurrency has been a pleasure. I'll avoid repeating > ALL my old thoughts and just highlight the KEY details. > > * Structured Concurrency is excellent for complex error-handling. > Receiving exceptions via the subtask makes all the error-handling less > painful. > * Structured Concurrency makes nesting scopes a breeze, a task I > historically found very painful to do. > * Inheritance allows me to take an existing Scope (now Joiner), and modify > only what I need to in order to modify it for my use case. Great for > reusing old strategies in new ways. > > Now for the new stuff -- having Joiner be the point of extension > definitely proved to be the right move imo. I didn't mention this in my > original message, but while it was easy to get a scope set up using > inheritance, it wasn't always clear what invariants needed to be > maintained. For example, the ensureOwnerAndJoined method. Was that > something we needed to call when inheriting? On which methods? Just join()? > > The Joiner solution is comparatively simpler, which actually meant that I > ended up creating way more Joiners, rather than only several STS'. Joiners > invariants are obvious, and there is no ambiguity on what is expected from > the implementor. > > Which, funnily enough, led to a slightly different problem -- I found > myself wanting an easier way to create Joiners. Since I was leaning on > Joiners so much more heavily than I was for STS, I ended up creating many > Joiners that do almost the same thing, with just minor variations. And > inheritance wasn't always the right answer, as I can't inherit from > multiple classes. Plus, most of my joiners were stateful, but I only wanted > the non-stateful parts of it. I could do composition, but it sort of felt > weird to delegate to multiple other Joiners. > > Part of me kept wondering how well a factory method, similar to the ones > for Collectors and Gatherers, might fare for Joiners. > > Regardless, even if we don't get that factory method, this library has > been a pleasure, and I can't wait to properly implement this once it goes > live. > > Thank you for your time and consideration. > David Alayachew > >