On 10 March 2025 03:55:21 GMT, Larry Garfield <la...@garfieldtech.com> 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]

Reply via email to