>  Most RFCs have an example in the introduction of what the proposed syntax 
> looks like in a small but meaningful example.  Please include such, as it 
> helps "set the stage" and provide context for the rest of the RFC.

usage examples are provided immediately after the API Overview, as agreed.

> As I've said before, I'd rather have keywords than functions for the main API.

As discussed earlier, introducing new keywords is better addressed in
a separate RFC.

> getAwaitingInfo(): array - Hell no, no struct arrays.  Make it a class.

The getAwaitingInfo function is intended to retrieve debugging
information that can be used for telemetry or debugging purposes.
Different reasons for suspending a coroutine may have different
metadata, which is difficult to standardize.
Therefore, an associative array with keys is used as the ideal data
structure for storing information without a contract, and one that is
easy to serialize.

> Function name strings should basically never be used again.  (Another 
> argument in favor of keywords.)
The question goes beyond the scope of this RFC.
However, what would be useful to discuss is the possibility of
narrowing the interface down to Closure. For some reason, a year has
already passed, and that discussion still has not happened.

>  "The non-blocking version of the file_get_contents function is not part of 
> this RFC." - Wait, I'm confused.
This is a consequence of the lack of agreement on what should be
included in an RFC and what should not. I will remove this block.

> The examples seem very inconsistent.  Some are using foo(...),
The term “inconsistency” cannot be applied in this case, since all
examples are consistent with subsets that belong to the same set.
In PHP, all these expressions are callable.

> - In Fibers, in the basic example, "start() blocks until the fiber completes" 
> - I assume that means it blocks the calling coroutine?  Or does it block the 
> whole system until it completes?
Non-blocking behavior is the default. Therefore, of course, it is the
coroutine that is blocked.

> - I have no idea what it means for coroutines to be "symmetric".  This is 
> stated as a thing, but I have no clue what that means.  That makes much of 
> the Fibers section incomprehensible.
There is a terminology error here. It should be “asymmetric.”:

>> Asymmetric coroutine mechanisms (more commonly denoted as semi-symmetric or 
>> semi coroutines) provide two control-transfer operations: one for invoking a 
>> coroutine and one for suspending it, the latter returning control to the 
>> coroutine invoker. >> While symmetric coroutines operate at the same 
>> hierarchical level, an asymmetric coroutine can be regarded as subordinate 
>> to its caller, the relationship between them being somewhat similar to that 
>> between a called and a calling routine.

In other words, according to the official PHP documentation, the
following conditions must be met:
>> Suspends execution of the current fiber. The value provided to this method 
>> will be returned from the call to Fiber::start(), Fiber::resume(), or 
>> Fiber::throw() that switched execution into the current fiber.

> - I will have to defer to the existing async gurus
This is not complex enough to require asking a guru.
Fibers transfer control according to the following scheme:
```
Fiber::start() -> Fiber::suspend() -> Fiber::resume()
FiberA               FiberB                      FiberA
```

A -> B -> A

This logic remains valid for coroutines as well:
```
Fiber::start() -> Fiber::suspend() -> Fiber::resume()
CoroA               CoroB                      CoroA
```

A -> B -> A

I hope someone actually read the Fibers RFC, right?

> If I'm reading that correctly, it means `span(very_long_function(...))` will 
> start a coroutine, but not assign it to a variable.
> So I cannot track it or refer to it, but it will still run in the background 
> until it completes, at which point it will get GCed.  Is that correct?
Yes.
The spawn function will return a Coroutine object, which can be used
like any other object. The reference count of such an object will be
2.
If the result of spawn is not used, the coroutine will live for as
long as it is executing.

> The FrankenPHP example linked to... doesn't seem to do anything to start a 
> coroutine.  I don't know what it's supposed to be demonstrating other than 
> FrankenPHP itself.
Here, FrankenPHP handles HTTP requests in separate coroutines. That
is, it demonstrates how coroutines can help improve performance for a
web server.
The coroutine is created inside the FrankenPHP extension, and the user
provides the request-handling function.
Thus, each request is handled in a separate coroutine.

> What is the difference then between $coroutine->finally() and 
> register_shutdown_function(), when the current coroutine happens to be main?
There is no difference.
Most likely, the finally handler will be invoked before
register_shutdown_function, although I am not 100% sure.

> Non-Async code can use Cancellation, but... what does that even mean or do?  
> Why would someone use it?
> This is sneaking in a 3rd error type without much guidance.  catch(Throwable) 
> is surprisingly common (rightly or wrongly), so this feels like a major 
> pothole potential.

In this RFC, there is no non-async code. Where does this text come from?

> Oh crap, Scopes are now a SEPARATE RFC, of similar length?
I thought that when you voted the previous version of the RFC, you had
at least read the first page. I see.
In fact, the Scope API was separated a long time ago.
This was done in order to reduce cognitive load.

> This seems mostly logical as a low-level API
The term *low-level* is used incorrectly here.
*Low-level* is applicable when an API exposes internal implementation
details or operates at a lower level of abstraction. For example,
drawing a pixel versus drawing a point. Drawing a pixel is low-level.
In this case, coroutines themselves (unlike Fibers in the past) are a
high-level abstraction that hides all implementation details from the
user.
If you analyze the API surface of Scope versus this RFC, you will see
that the APIs are at the same level of abstraction. Therefore, neither
the Scope API nor the Async Base API is low-level.

>  I want a *safe* API.  I am not convinced those are compatible.  And I 
> certainly do not want to see the low-level API in one release and then have 
> to wait for the next release for the safer API.

In programming, the term “safe” is used in different meanings and is
usually not applied in the context in which you are using it.
I do not recommend using the term **safe** in this case, as the U.S.
security services might read this message and ban the use of PHP on
the grounds that PHP has no *safe* variables.
In this case, the code remains safe even without the Scope API.

> Having pipes and PFA in separate releases is bad enough. :-)
It was originally assumed that the Scope API, as well as the Context
API, would be approved immediately after this RFC.
However, given the pace of the discussion, or rather the complete lack
of it, this seems unlikely.

> That this allows for zombie coroutines or "lost" background coroutines to 
> exist is, to me, a major problem.
You wrote that something is a problem, but you forgot to explain why
it is a problem.
The Scope API does not prohibit the use of zombie coroutines.

> As I've said before, I don't like await, spawn, etc. being free-standing 
> functions rather than keywords.  That is very limiting on the syntax they can 
> use.  It also means, as the examples show, we get this pattern very often:
Nevertheless, this is the only reasonable solution for the gradual
approval of the API. Moreover, even if keywords are added later, the
functions will not need to be removed.

> $result = $fn |> spawn(...) |> await(...);
(wipes away bloody tears)
Oh God, why am I reading this :)

A pipe is sequential execution of something.
That means if something asynchronous is called inside a pipe, the pipe
must wait for it out of the box, without any additional functions.
In other words, a “dereferencing” operation of the future must be applied:

```php
$result = $data |> strtolower(?) |> spawn(someFunction(...), ?) |>
strtoupper(?);
```
I haven’t studied the new syntax yet, but I think the idea is clear.
In other words, the pipe must wait for the completion of the
asynchronous operation.

If PHP can adopt a new, cleaner syntax for closures, then it will be
possible to introduce a new spawn keyword for coroutines and create a
single, elegant syntax. But in essence, this changes nothing.

----
Ed.

Reply via email to