> The example I gave is probably a good one? If I'm writing framework-y code, 
> how do I decide to await once, or in a loop? In other words,
> how do I detect whether an Awaitable is idempotent or will give a different 
> result every time? If I'm wrong, I could end up in an infinite loop, or 
> missing results.
> Further, how do I know whether the last value from an Awaitable is the last 
> value? I think if you could illustrate that in the RFC or change the 
> semantics, that'd be fine.

If a function knows nothing about the object it’s awaiting, it’s
equally helpless not only in deciding whether to use while or not, but
also in determining how to handle the result.

As for the infinite loop issue, the situation depends on the
termination conditions. For example:

```php

$queue = new Queue();

// Rust future-based
while(true) {
    $future = $queue->next();
    if($future === null) {
          break;
    }

    await($future);
}
```

or

```php
$queue = new Queue();

// Awaitable style
while($queue->isClosed() === false) {
    await($queue);
}

```

In other words, a loop needs some method that limits its execution in
any case and it’s hard to make a mistake with that.

> Accidentally sent too early: but also, what if there are multiple awaiters 
> for a non-idempotent Awaiter? How do we handle that?

All of this completely depends on the implementation of the awaited object.

The Awaitable contract does not define when the event will occur or
whether it will be cached. it only guarantees that the object can be
awaited.
However, the exact moment when the object wakes the coroutine and what
type of data it provides are all outside the scope of the awaiting
contract.

In Rust, it’s common practice to use methods that create a new Future
(or NULL) when a certain action needs to be awaited, like:

```rust
while let Some(v) = rx.recv().await {
    println!("Got: {}", v);
}
```

Multiple awaits usually appear as several different `Future` instances
that can be created by the same awaitable object.
However, the Rust approach doesn’t fundamentally change...

If the internal logic of an Awaitable object loses an event before a
Future is created, the behavior is effectively the same as if the
Future never existed.

The advantage of the Rust approach is that the programmer can clearly
see that a Future is being created (rx.recv() should return Future new
one or the same?). (Perhaps the code looks more compact)
But they still have to read the documentation to understand how this
Future completes, how it’s created, and what data it returns. Whether
the last message is cached or not, and so on.

In summary, a programmer must understand what kind of object they’re
actually working with. It’s unlikely that this can be avoided.

Reply via email to