Re: PHP True Async RFC Stage 4

From: Date: Wed, 22 Oct 2025 09:35:16 +0000
Subject: Re: PHP True Async RFC Stage 4
References: 1 2 3 4 5 6 7 8 9 10  Groups: php.internals 
Request: Send a blank email to internals+get-128898@lists.php.net to get a copy of this message
> The example I gave is probably a good one? If I'm writing framework-y code, how do I > decide to await once, or in a loop? In other words, > how do I detect whether an Awaitable is idempotent or will give a different result every time? > If I'm wrong, I could end up in an infinite loop, or missing results. > Further, how do I know whether the last value from an Awaitable is the last value? I think if > you could illustrate that in the RFC or change the semantics, that'd be fine. If a function knows nothing about the object it’s awaiting, it’s equally helpless not only in deciding whether to use while or not, but also in determining how to handle the result. As for the infinite loop issue, the situation depends on the termination conditions. For example: ```php $queue = new Queue(); // Rust future-based while(true) { $future = $queue->next(); if($future === null) { break; } await($future); } ``` or ```php $queue = new Queue(); // Awaitable style while($queue->isClosed() === false) { await($queue); } ``` In other words, a loop needs some method that limits its execution in any case and it’s hard to make a mistake with that. > Accidentally sent too early: but also, what if there are multiple awaiters for a non-idempotent > Awaiter? How do we handle that? All of this completely depends on the implementation of the awaited object. The Awaitable contract does not define when the event will occur or whether it will be cached. it only guarantees that the object can be awaited. However, the exact moment when the object wakes the coroutine and what type of data it provides are all outside the scope of the awaiting contract. In Rust, it’s common practice to use methods that create a new Future (or NULL) when a certain action needs to be awaited, like: ```rust while let Some(v) = rx.recv().await { println!("Got: {}", v); } ``` Multiple awaits usually appear as several different Future instances that can be created by the same awaitable object. However, the Rust approach doesn’t fundamentally change... If the internal logic of an Awaitable object loses an event before a Future is created, the behavior is effectively the same as if the Future never existed. The advantage of the Rust approach is that the programmer can clearly see that a Future is being created (rx.recv() should return Future new one or the same?). (Perhaps the code looks more compact) But they still have to read the documentation to understand how this Future completes, how it’s created, and what data it returns. Whether the last message is cached or not, and so on. In summary, a programmer must understand what kind of object they’re actually working with. It’s unlikely that this can be avoided.

« previous php.internals (#128898) next »