Hello Larry
Regarding the phrase about “problems with mutable shared state”.
In this context, when I say “problem,” I mean something that
significantly worsens development. “Not a problem” does not mean that
errors never occur. It means that resolving them takes an acceptable
amount of time. This phenomenon has reasonable explanations:
1. Developers usually know where they use global state. And even if
they don’t, they know that this is the first thing to check. That
helps a lot.
2. Bugs involving shared memory are usually easy to reproduce (which
is rare in asynchronous programming). This drastically reduces
debugging time.
3. In a single-threaded environment, shared-state bugs are much
simpler. For example, the probability of corrupting data structures is
relatively low.
4. In PHP projects, shared state is typically used in a small set of
scenarios, and these scenarios are usually simple, which also
minimizes the time needed to fix issues.
For example: some global variable stores a SessionId. And then it
turns out that an action was recorded not for the user who performed
it, but for another one with a different session. In most cases, the
bug report alone already points you directly to where you need to
look.
My point is not that you should ignore shared-memory bugs, but that
you shouldn’t fear them or treat them as something huge.
I also want to remind that in programming there are no “bad”
approaches or technologies. Shared mutable state is a very useful
thing and should be used. For caching, for storing session data, for
access-rights memoization, and so on. You don’t need to avoid shared
state. You need good tools, patterns, and proper practices. As for
language-level abstraction, features like `local $var`, effects, and
context will help make the code safer.
Monads would also fit PHP well, as they allow expressing parallelism
better than procedural code.
> That's what I think we all want to NOT have in PHP.
Exactly. PHP exists to save money, not to spend it. Recently there was
an article about Python describing the problems caused by having
multiple runtimes.
> Third: So my question would be, is there a practical middle-ground?
> Is there a syntax and semantics we could define that would cover *most* edge
> cases existing code may have involving shared mutable state automatically
Based on the current state of programming languages, there is no good
solution. Only radical ones like Actors, Arenas, and so on. All of
them rely on complete memory isolation. But that’s not the point. The
point is that PHP still has legacy code, and you cannot just throw it
away.
> the RFC right now says "any IO operation, implicitly, hope that's OK."
Go does the same thing, and it’s a very convenient mechanism.
There is a small percentage of cases where this breaks the logic.
Here is one of them:
```php
$start = microtime(true);
$data = file_get_contents('data.txt');
$elapsed = microtime(true) - $start;
if ($elapsed > 0.001) {
echo "Reading took too long\n";
}
```
The code breaks only in two cases:
1. When there is usage of mutable shared memory/shared resource
2. When there is logic based on a timer
Yes, such code will break inside a coroutine. But should we be afraid
of that? I don’t think so. The likelihood of this kind of logic is
very low. And if needed, this case can be explicitly documented.
Besides this case, special attention is also needed for:
* libraries that use sockets
* libraries that use threads
* libraries that use processes
But this does not mean there will necessarily be major or serious
problems adapting the code. PHP already has experience with Swoole,
and Swoole works exactly the same way as the code in this RFC. For
example, adapting the RabbitMQ library for Swoole required changing
about 10–20 lines of code, roughly 2–3 days of work. Most of the time
was spent on testing.
Regarding the hybrid function-tainting model, it is designed for
compilers or static analysis. For PHP, it could be implemented like
this:
```php
#NoAsync
function myFun() {
asyncFun(); // Error <---
}
function asyncFun() {}
```
This is a solvable task for static analysis.