Re: PHP True Async RFC Stage 4

From: Date: Wed, 22 Oct 2025 17:24:18 +0000
Subject: Re: PHP True Async RFC Stage 4
References: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  Groups: php.internals 
Request: Send a blank email to internals+get-128907@lists.php.net to get a copy of this message
On Wed, Oct 22, 2025, at 10:30 AM, Edmond Dantes wrote: >> This isn't even the same example. We're not talking about type juggling, but an >> interface. Mixed is not an object nor an interface. > Why? > Type and Interface are contracts. > >> The "FutureLike" type is exactly what I'm arguing for! > > I have nothing against this interface. My point is different: > 1. Should the await and awaitXX functions accept only Future? > 2. Should Awaitable be hidden from the PHP userland? > >> foreach($next = await($awaitable)) { } > What’s the problem here? The object will return a result. > If the result is iterable, it will go into the foreach loop. An > absolutely normal situation. > >> error: multiple usages of multi-shot Awaitable; you may get a different result on each >> invocation of await() > Why can’t you call await twice? What’s illegal about it? > If it’s a Future, you’ll get the previous result; if it’s an > Awaitable, you’ll get the second value. > But the correctness of the code here 100% depends on the programmer’s intent. And that's exactly the problem. The correctness cannot be inferred without asking the programmer. There is, obviously, no such thing as idiot-proof code, as the world will always create a better idiot. But we should still strive to be idiot-resistant. There are two general ways of doing that: 1. Affordances - Basically, it should be hard to use wrong. 2. Construction - It should be impossible to use wrong in the first place. (Ie, a compile error.) The classic example is US electrical plugs vs EU plugs. They *should* be different shapes, because they're different voltages. If you plug an unsuspecting device into the wrong voltage, it goes boom. So the different plug interfaces make it patently obvious that you're doing something wrong because they don't fit together (construction), and if you use an adapter that is your signal that you need to worry about voltage conversion (affordance). Using the same type for something that can be read only once vs something that should be read multiple times is equivalent to using the same plug for both 120v and 240v current. (Or USB-C using the same plug for 8 different speeds, 5 different power delivery levels, and sometimes no data at all. It sucks.) The developer needs to "just know" which one is intended, because the code doesn't tell them. That's a problem. Instead, like Rob said, there should be a one-shot object that dies as soon as it is successfully read. That is guaranteed to be single-use, and reading it multiple times is detectable by a static analysis tool as "you clearly are doing this wrong, no question." Then a multi-read object is... an Iterable that produces those single shot objects. I'm not sure if that even needs its own object that implements Iterable, or if it's OK to not define it and just say it's any iterable<Awaitable>. (So, a generator would work just as well.) I'm leaning toward the latter, but there may be uses for the former, not sure. But having a "dual voltage" awaitable object is exactly the sort of footgun many of us are talking about. The contract is under-specified, so it's too easy for the developer to be "holding it wrong" and plug it into the wrong wall socket. Boom. --Larry Garfield

« previous php.internals (#128907) next »