On Sat, Mar 8, 2025, at 00:21, Rowan Tommins [IMSoP] wrote: > On 07/03/2025 22:01, Larry Garfield wrote: > > Is that what you're suggesting? If so, I'd have to think it through a bit > > more to see what guarantees that does[n't] provide. It might work. (I > > deliberately used spawn instead of "await" to avoid the mental association > > with JS async/await.) My biggest issue is that this is starting to feel > > like colored functions, even if partially transparent. > > > Yes, that's pretty much what was in my head. I freely admit I haven't > thought through the implications either. > > > > My biggest issue is that this is starting to feel like colored functions, > > even if partially transparent. > > > I think it's significantly *less* like coloured functions than passing > around a nursery object. You could almost take this: > > async function foo($bar int, $baz string) { > spawn something_else(); > } > spawn foo(42, 'hello'); > > As sugar for this: > > function foo($bar int, $baz string, AsyncNursery $__nursery) { > $__nursery->spawn( something_else(...) ); > } > $__nursery->spawn( fn($n) => foo(42, 'hello', $n) ); > > However you spell it, you've had to change the function's *signature* in > order to use async facilities in its *body*. > > > If the body can say "get current nursery", it can be called even if its > *immediate* caller has no knowledge of async code, as long as we have > some reasonable definition of "current". > > > -- > Rowan Tommins > [IMSoP] >
The uncoloring of functions in PHP is probably one of the most annoying aspects of fibers, IMHO. It's hard to explain unless you've been using them awhile. But, with colored functions, the caller has control over when the result is waiting on -- it could be now, it could be in a totally different part of the program, or not at all. With fibers, the author of the function you are calling has control over when the result is waited on (and they don't have control over anything they call). This can create unpredictable issues when writing code where a specific part wrote some code thinking it had exclusive access to a property/variable. However, someone else changed one of the functions being called into an async function, making that assumption no longer true. With colored functions, the person making changes also has to update all the places where it is called and can validate any assumptions are still going to be true; uncolored functions means they almost never do this. This results in more work for people implementing async, but more correct programs overall. But back to the awaiting on results. Say I want to read 10 files: for ($i = 0; $i < 10; $i++) $results[] = file_get_contents($file[$i]); Right now, we have to read each file, one at a time, because this is synchronous. Even with this RFC and being in a fiber, the overall execution might be non-blocking, but the code still reads one file after another sequentially. Fibers do not change this. With this RFC (in its original form), we will be able to change it so that we can run it asynchronously though and choose when to wait: for($i = 0; $i < 10; $i++) $results[] = async\async(fn($f) => file_get_contents($f), $file[$i]); // convert $results into futures somehow -- though actually doesn't look like it is possible. $results = async\awaitAll($results); In that example, we are deliberately starting to read all 10 files at the same time. If we had colored functions (aka, async/await) then changing file_get_contents to async would mean you have to change everywhere it is called too. That means I would see that file_get_contents is synchronous and be able to optimize it without having to even understand the reasoning (in most cases). I was a user of C# when this happened to C#, and it was a pain... So, at least with PHP fibers, this won't be AS painful, but you still have to do some work to take full advantage of them. I kind of like the idea of a nursery for async, as we could then update file_get_content's return type to something like string|false|future<string|false>. In non-async, you have everything behave as normal, but inside a nursery, it returns a future that can be awaited however you want and is fully non-blocking. In other words, simply returning a future is enough for the engine to realize it should spawn a fiber (similar to how using yield works with generators). In any case, I believe that a nursery requires the use of colored functions. That may be good or bad, but IMHO makes it much more useful and easier to write correct and fast code. — Rob