Hey Josh,

> > This is a very valid concern to have. However, this code won't simply
> break if executed asynchronously.
> > It only breaks if the same method (or other methods making use of the
> same state) is executed concurrently on that object.
>
> I understand this, but of course this will be common in programs where
> fibers are used, and the nature of this proposal means that fibers
> will potentially be highly insidious and quite unpredictable in their
> reach.
>

Concurrent operations on stateful, mutable objects are certainly a risk and
concurrency shouldn't be introduced without thinking about the
consequences. Care must be taken if objects are used across different
fibers concurrently, unless you use global state, then you'll have a harder
time adding concurrency to your application.


> > If you can see the race condition here, you can probably also see the
> race condition in the original snippet above.
>
> The difference is that in the second case, the developer has
> *explicitly opted into the underlying call being async*. I.e. they
> expect it, and can design with it in mind.
>

While the developer opted into async / non-blocking I/O, they still might
not have thought about concurrent operations on that same object.

> Being able to use the type system is a concern the RFC solves, but that's
> rather just nice-to-have. The relevant problem is the call stack pollution
> or "What color is your function" problem. It simply doesn't make sense for
> applications and libraries to offer an async and non-async interface for
> everything. Due to the "What color is your function" problem, there can't
> be a gradual migration to non-blocking I/O, which will mostly result in
> non-blocking I/O simply not being supported by the majority of libraries,
> making it basically non-viable in PHP.
>
> Perhaps we could rather make fibers *opt in* at the *callsite*
> (similar to goroutine calls) in order to prevent functions
> unexpectedly being executed asynchronously due to faraway changes.
> This would be safe and predictable while also avoiding the "What color
> is your function" problem. For example
>
>     private function capturePayment(): void
>     {
>         $paymentRequest = preparePaymentRequest($this->currentOrder);
>         // allow, but don't require, the underlying call to use
> fibers. Callers higher up the stack would also have to opt in
>         async $this->paymentGateway->capturePayment($paymentRequest);
>
> $this->currentOrder->setTransactionId($paymentRequest->getTransactionId());
>     }
>
> With this approach, APIs we'd avoid the "what colour is your function"
> problem without sacrificing the safety that we really need in e.g.
> ecommerce.
>

This doesn't really avoid the "what color is your function" problem, as
you'd have to mark all function calls with "async" then, eventually
resulting in every PHP function call having to be prefixed with "async".

Rather than marking methods with "synchronized" as mentioned before, it
might be more feasible to mark methods with a keyword if they allow
concurrent operations. I'll have to research which options are viable.

Best,
Niklas

Reply via email to