I’d like you to have the full information necessary to make an
informed decision.

There are two or more channel objects that need to be awaited. How
should this be implemented?

Currently
```php
[$result1, $result2] = awaitAny($channel1, $channel2);
```

With Futures:
```php
// Like Rust
[$result1, $result2] = awaitAny($channel1->recv(), $channel2->recv());
```

Rust:
```rust
tokio::select! {
    msg = channel1.recv() => println!("Got from 1: {:?}", msg),
    msg = channel2.recv() => println!("Got from 2: {:?}", msg),
}
```

Swift:
```swift
async let result1 = fetchData1()
async let result2 = fetchData2()
let (r1, r2) = await (result1, result2)
```

Although both Swift and Rust create a Future under the hood, that’s
part of the internal implementation, not the user-facing contract.

What I dislike about the Future example is that it creates an object
that isn’t actually needed.
What I like about it is that it clearly shows what action is being awaited.

When executing the awaitXX operation in a loop for such scenarios, the
programmer will pay for the visual clarity of the code with extra
operations to create a PHP object.
Are you sure this is what you really want?

I want to caution you against directly comparing PHP, Rust, and Swift.
What a compiler and zero-abstraction languages can do, PHP cannot.
And the approaches used by Rust or Swift cannot be directly applied to
a language without a compiler.

I have no objection to doing it the way you prefer, but keep in mind
that chasing what looks elegant often leads to poor decisions. It’s
better to think it over a few times.

Reply via email to