On 10 March 2025 03:55:21 GMT, Larry Garfield <[email protected]> wrote:
>Support for nested blocks is absolutely mandatory, whatever else we do. If you cannot nest one
>async block (scheduler instance, coroutine, whatever it is) inside another, then basically no code
>can do anything async except the top level framework.
To stretch the analogy slightly, this is like saying that no Linux program could call fork() until
containers were invented. That's quite obviously not true; in a system without containers, the
forked process is tracked by the single global scheduler, and has a default relationship to its
parent but also with other top-level processes.
Nested blocks are necessary *if* we want automatic resource management around user-selected parts of
the program - which is close to being a tautology. If we don't provide them, we just need a
defined start and end of the scheduler - and Edmond's current suggestion is that that could be
an automatic part of the process / thread lifecycle, and not visible to the user at all.
>This function needs to be possible, and work anywhere, regardless of whether there's an
>"open" async session 5 stack calls up.
>
>function par_map(iterable $it, callable $c) {
> $result = [];
> async {
> foreach ($it as $val) {
> $result[] = $c($val);
> }
> }
>return $result;
>}
This looks to me like an example where you should not be creating an extra context/nursery/whatever.
A generic building block like map() should generally not impose resource restrictions on the code
it's working with. In fact as written there's no reason for this function to exist at all
- if $c returns a Future, a normal array_map will return an array of Futures, and can be composed
with await_all, await_any, etc as necessary.
If an explicit nursery/context was required in order to use async features, you'd probably want
instead to have a version of array_map which took one as an extra parameter, and passed it to along
to the callback:
function par_map(iterable $it, callable $c, AsyncContext $ctx) {
$result = [];
async {
foreach ($it as $val) {
$result[] = $c($val, $ctx);
}
}
return $result;
}
This is pretty much just coloured functions, but with uglier syntax, since par_map itself isn't
doing anything useful with the context, just passing along the one from an outer scope. An awful lot
of functions would be like this; maybe FP experts would like it, authors of existing PHP code would
absolutely hate it.
The place I see nested async{} blocks *potentially* being useful is to have a handful of key
"firewalls" in the application, where any accidentally orphaned coroutines can be
automatically awaited before declaring a particular task "done". But Daniil is probably
right to ask for concrete use cases, and I have not used enough existing async code (in PHP or any
other language) to answer that confidently.
Rowan Tommins
[IMSoP]