On Wed, 13 Apr 2022 at 01:29, VinÃcius dos Santos Oliveira
https://github.com/boostorg/asio/blob/a7db875e4e23d711194bcbcb88510ee298ea29...
The abstraction is built for the specific application only. It'll carry its policies builtin.
Unless you factor out those application specific *policies* to end-up with a generic *session*, that is not only useful on the chat_server, but everywhere. I am claiming you can do that without losing generality and without being incompatible with the *Asio the way*. I find myself however repeating myself often, so I think we should agree on something first, before the discussion gets even more unintelligible. So let me start again My Redis client class, which I call high-level-API, works to a large extent just like the chat_session I pointed you at https://github.com/boostorg/asio/blob/a7db875e4e23d711194bcbcb88510ee298ea29... but adapted for Redis and not a chat_server. So if you have a problem with that example, we have to clarify before proceeding. In that example you see a - reader: a loop on async_read - writer: a loop on async_write. I am also claiming there is no way to avoid these loops because - you have to keep constantly reading from a tcp socket for as long as it is open, for obvious reasons. - you need to loop on async_write to process the message queue. If I don't provide these loops in my library, users will have to write their own, simply because that is how communication of the tcp layer works. Now as to why you can't avoid callbacks. The reader implementation looks like awaitable<void> reader() { for (std::string read_msg;;) { std::size_t n = co_await boost::asio::async_read_until(..., use_awaitable); room_.deliver(read_msg.substr(0, n)); read_msg.erase(0, n); } } As you see, the room_.deliver call is application specific and only useful for the chat server. To make it useful elsewhere, you have to call a user provided callback, so it becomes generic // generic version. awaitable<void> reader(callback ck) { for (std::string read_msg;;) { std::size_t n = co_await boost::asio::async_read_until(..., use_awaitable); ck(msg); read_msg.erase(0, n); } } The same thing applies to the writer. In other words, high-level applications that provide a reader and writer like that, will invariably have to use a callback. The biggest concern I had during development was whether co_yield were a better way to deliver the data, instead of callback. That however requires coroutine support and C++20 from all users. It is also an annoyance as users would still have to write the loops themselves again, so it is not a better solution. Marcelo