My experience with Structured Concurrency

David Alayachew davidalayachew at gmail.com
Sun Aug 17 21:46:35 UTC 2025


Can you give an example? I used Anonymous classes in my solutions, but most
of them were just based off of the Joiner interface.

I guess I could introduce some state into the abstract class, and then just
tweak it for my needs. And obviously, I'd need a new abstract class for
each "category" of joiner. Then from there, just implement it inline,
making each inline case cheaper. Is that what you are hinting to?

On Sun, Aug 17, 2025, 5:28 PM robert engels <rengels at ix.netcom.com> wrote:

> Isn’t this a perfect use of an anonymous class with a base class?
>
> On Aug 17, 2025, at 4:00 PM, David Alayachew <davidalayachew at gmail.com>
> wrote:
>
> > I will guess that #1, #2, and #5 are relatively
> > simpler Joiner implementations, is there really
> > any benefit to use composition or inheritance here?
>
> Sorry, I have been unclear. Let me clarify.
>
> Yes, it is not hard at all to implement #1, #2, and #5 at all. But I don't
> have 5 joiners. I have well past 30 of them.
>
> Most of my joiners are very similar to each other. The 5 I showed you are
> most of the major "categories" of joiners I would make. But each category
> would have many derivatives of it.
>
> For example, #2 had a derivative that was the same, but for multiple
> Exception types as opposed to just one. Another derivative of #2 would go
> past a type test, and actually look at the fields of the Exception (like
> HTTP Error Code). Yet another would go one level deep, in case the
> exception was wrapped (like wrapping an HTTP Exception in a
> RuntimeException).
>
> So I started making a whole new class each time I wanted to do almost the
> same thing. But you start to run out of names that accurately describe what
> you are doing. And yeah, some joiners are going to be heavily reused, so it
> makes sense for them to have a whole type (and maybe source file). But many
> won't either.
>
> Once I realized that I was making a bunch of the same thing with minor
> variations, that's when I started thinking about inheritance and
> composition. Sorry if I made it sound like that's what I first jumped to.
> No, I thought about inheritance and composition because those are usually
> the default answers to the question of "How do I do what T is doing, but
> with a minor variation?"
>
> But inheritance and composition didn't get me very far for these joiners,
> which is what I was trying to say in my original email. Inheritance with
> state is error-prone (from my experience). And composition meant that I was
> making my code brittle. What if those methods I am depending upon need to
> change?
>
> So I went back to making each joiner be its own thing. In reality, most of
> my custom Joiners were either a simple record implementing the Joiner, or
> an anonymous class. Records are fine, but you start to run out of
> reasonable names when you have 5 different records that do close to the
> same thing. I kind of found a compromise by creating the record Joiner
> inside the method itself that I am working in (or the class if other
> methods need it too). That way, it's scoped off from the rest of the world.
> But considering how many I was making, it felt like a clunky solution. I'm
> fine peppering my code base with inlined records all over the place *as
> long as those records don't have a body*. But once they do, it starts to
> get annoying, and makes the code harder to read and skim.
>
> From there, I thought about making a factory. You know the rest of the
> story.
>
> > For #4 and #5 then its surprising that there is RPC
> > or split/join in the onComplete method.  The
> > onComplete method is called with the completed
> > subtask and any exception/error executing
> > onComplete isn't going to change the subtask
> > status. Is there a reason you've chosen to put
> > that code there rather than in the subtasks?
>
> Yeah. Long story short, if that RPC call or the nested scope fails, well
> the literal goal that I created this scope to do (contruct an object) has,
> in effect, failed. That's grounds to just throw an exception and see if
> someone upstream can handle it. Maybe a retry or something.
>
> To me, it felt like I was keeping inline with what onComplete was trying
> to do -- sort of be an AOP-like post-processing joinpoint. If the contents
> of onComplete fails, well then the goal was unattainable anyways, so
> killing the scope via thrown exception doesn't feel wrong. And the
> exception will propagate, so it felt like I was following right along with
> how the spec intended things to go. Granted, I certainly am marching on the
> edge here, I'll concede that.
>
> > (for his API then the question as to "where" to
> > put code is a good discussion as it may not be
> > always obvious whether to code should execute in
> > the subtask, in the Joiner handling subtask
> > completion, or in the main task in the processing
> > after join.
>
> I would love a short guide on what code to put in what place. This looks
> to be a pretty integral API for handling a large number of tasks moving
> forward, so I see value in it.
>
>
> On Sun, Aug 17, 2025 at 1:13 PM Alan Bateman <alan.bateman at oracle.com>
> wrote:
>
>> On 16/08/2025 20:23, David Alayachew wrote:
>>
>> :
>>
>> Sure. Let me highlight 5 of them. Let me know if you need more examples
>> -- I have about 30+ custom implementations.
>>
>>
>> Thanks for sharing this selection.
>>
>> I will guess that #1, #2, and #5 are relatively simpler Joiner
>> implementations, is there really any benefit to use composition or
>> inheritance here?
>>
>> For #4 and #5 then its surprising that there is RPC or split/join in the
>> onComplete method.  The onComplete method is called with the completed
>> subtask and any exception/error executing onComplete isn't going to change
>> the subtask status. Is there a reason you've chosen to put that code there
>> rather than in the subtasks? (for his API then the question as to "where"
>> to put code is a good discussion as it may not be always obvious whether to
>> code should execute in the subtask, in the Joiner handling subtask
>> completion, or in the main task in the processing after join.
>>
>> -Alan
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250817/dc91425b/attachment.htm>


More information about the loom-dev mailing list