> On Oct 23, 2025, at 04:18, Rob Landers <[email protected]> wrote:
>
> On Thu, Oct 23, 2025, at 09:59, Edmond Dantes wrote:
>>
>>
>> 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);
>> ```
>>
> As for which one I'd rather have, I'd rather have the one where my examples
> hold true:
>
> assert(awaitAll($a, $b, $c) === [await($a), await($b), await($c)]);
>
> It's clear what it does and that it is just a shorthand. When that fails, we
> have issues.
>
> — Rob
Just to add to this, in Swift, a Task (the analogue to this proposal's
Coroutine) can emit, exactly once, a value or an error (exception). Attempting
to read its value (or error) multiple times gets you the same value back. This
is very handy in memoization patterns.
In this example, multiple readers can call getImage() with the same id and get
a value, regardless of whether they're the first (which kicks off image
loading), whether the image loading has completed, or whether the image load is
still in progress. (Technically, one could omit the LoadingBox wrapper
entirely, but that would cause the Task to persist after it's completed, and
that's a more expensive structure than a simple enum.)
```swift
private enum LoadingBox<T : Sendable> {
case inProgress(Task<T, Never>) //Task<Success, Failure>
case ready(T)
var value: T {
get async {
switch self {
case .inProgress(let task):
return await task.value
case .ready(let value):
return value
}
}
}
}
private var imageCache: [ImageId : LoadingBox<Image>] = [:]
func getImage(_ id: ImageId) async -> Image {
if let cache = imageCache[id] {
return await cache.value
}
let task = Task { ...load the image... }
imageCache[id] = task
return await task.value
}
```
Ultimately, I would want to be able to write code such as this in PHP (with the
generics, of course, but I'm not holding my breath).
If coroutines sometimes return single values and sometimes return multiple
values, it becomes much harder to write a generic async cache/memoization
system, because you can't indicate via the type system that a single value is
expected.
-John