On 11/10/2023 14:08, Klemens Morgenstern wrote:
I find the suggestions that C++ 20 coroutines needs to be somehow in the name convincing. Exactly what form it should take I’ll leave up to the author and community to negotiate, but “Boost.Async” is definitely not a name with good buy-in in the Boost community. It cannot be named “Boost.Async” if it is to enter Boost.
How do we judge what is acceptable to the boost community? Because there might always be someone to object to it.
I'll compose a list and start a separate thread.
I don't claim it'll be easy, but there was strong consensus that the current name must go.
There is left_select, which goes strictly left to right. Would this criteria be satisfied if I renamed left_select to select, and the current select to `unordered_select` or `random_select` ?
The review objections where to naming that operation "select" at all. Select for 99% of C and C++ users is something which does not cancel the other waiters on return. Several mentioned how surprising it was, for them Select is something which returns when something is ready and then code might do stuff like cancel things. I don't think there is anything wrong with the current semantics of the operation, except its name. `select_cancelling_others()` would be fine, but I'm sure a shorter name is possible without the BSD sockets type connotations.
- Andrzej took issue with the design of the generators, and I can see why. However, out in real world code land, C++ coroutine generators have surprisingly large amount of design variation. I’ve seen ones which you loop on testing them for boolean true, I’ve seen others which loop on their iterators, I’ve even seen ones which don’t implement either boolean true nor iterators and require you to call a `value()` member function which returns an Optional. Why? No idea, people seem to innovate uselessly here for some reason. I think it wise to adhere to `std::generator` from the standard, and do exactly what it does. From my reading of Async’s `generator`, whilst it has extensions e.g. the invocable call operator, the only thing missing is the iterator interface to make it implement `std::generator` and I don’t see any obvious reason why an iterator interface can’t be added here?
The reason is that we don't have "async for". I would need to resume the generator on increment, but if `itr++` is an awaitable expression that needs to be co_awaited, it's not an iterator. If there was an async for (or a common pattern) I'd make generator work with it.
Y'see I don't see the need for async for. That's separate to this. `std::generator` provides iterators. When you iterate one of its iterators the coroutine gets resumed and it yields a new value. The reason `std::generator` is like this is because it can be called from non-coroutine code, so `co_await` isn't available. Implied in this is iterator implementations must pump the coroutine by hand. This is very straightforward for the simple case, it gets harder if the generator suspends on say i/o. Then your generator iterator implementation needs to pump the event loop too. This isn't a hard to surmount problem to solve for Boost.Async I think. And I think a Boost level library does need to implement what the C++ standard demands, even if it's a bit dumb. Down the road if WG21 ever gets round to async for, support for that can be added later. I have also wondered if a `BOOST_CO_ASYNC_FOR` macro couldn't implement async for right now. And finally, I have a gut feeling without proof nor evidence that it *may* be possible to detect from a macro whether it is being invoked by a coroutine or not, and if so, "do the right thing" based on caller context. So a `BOOST_ASYNC_FOR()` macro which does the right kind of for loop for iterating a generator depending on caller may be achievable. Niall