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

Reply via email to