Re: PHP True Async RFC Stage 4

From: Date: Thu, 16 Oct 2025 14:42:39 +0000
Subject: Re: PHP True Async RFC Stage 4
References: 1 2 3 4 5 6 7 8 9  Groups: php.internals 
Request: Send a blank email to internals+get-128855@lists.php.net to get a copy of this message

On Thu, Oct 16, 2025, at 15:19, Edmond Dantes wrote:
> > Would it be better to instead of having ->awaitCompletion (which feels like an implicit
> > implementation of Awaitable without an explicit implmentation -- which is the part that was
> > bothering me), maybe having something like ->joinAll() or ->joinOnCancellation()?
> > That way someone like me won't come along and wrap them in an Awaitable because it
> > looks Awaitable.
> 
> For example, you have an interface DataBaseAdmin with a removeDB()
> method and a class that implements it.
> You need to be able to delete the database, but with an additional
> condition. So you create a decorator class with a method
> ContextualDBAdmin::removeDBWhen($extraRules).
> 
> As a result, the decorator class is logically associated with the
> DataBaseAdmin interface.
> 
> The question is: **so what?**

I think we might be talking past each other a little.

You said earlier that one of the goals here is to prevent misuse (e.g. unbounded or foreign awaits).
I completely agree and that’s exactly why I’m suggesting a rename. From the outside, a method
called awaitCompletion() looks and behaves like an Awaitable, even though the type explicitly
isn’t one. That contradiction encourages people to wrap it to “make it awaitable,” which
re-introduces the very problem you’re trying to avoid.

Renaming it to something like joinAll() or joinAfterCancellation() keeps the semantics intact while
communicating the intent: this isn’t a future; it’s a container join. That small change would
make the interface self-documenting and harder to misuse.

> 
> > It also might be a good idea to make specifying a timeout in ms mandatory, instead of a
> > taking an Awaitable/Cancellation.
> 
> The idea is correct, but there will definitely be someone who says
> they need more flexibility.
> And it's true you can create a DeferredCancellation and forget to
> finish it. :)
> 
> There are a lot of such subtle points, and they can be discussed endlessly.
> But I wouldn’t spend time on them.

That's what we are here to do, no? Discussion is useful if it makes things better than the sum
of their parts.

> > It also might be good to provide a realistic looking example showing a "bad
> > case" of how this is dangerous instead of simply saying that it is, showing how a scope is not
> > a 'future',
> > but a container, and preemptively mention TaskGroups, linking to the future scope (which
> > it should also probably be listed there as well).
> 
> 1. It’s very difficult to write a realistic example that’s still small.

I'll give it a go:

$scope = new Scope();

// Library code spawns in my scope (transitively)
$scope->spawn(fn() => thirdPartyOperation()); // may spawn more

// Looks innocent, but this can wait on foreign work:
$scope->awaitCompletion(Async\timeout(60000)); // rename -> joinAll(...)?

> 2. The TaskGroup or CoroutineGroup class is left for future
> discussion. In the final documentation, it will be exactly as you
> suggested.

My point is that it wasn't listed in "future scope" of the RFC, though they're
mentioned throughout the document, in passing.

— Rob


Thread (104 messages)

« previous php.internals (#128855) next »