I decided to immerse into C++ coroutines, have read some articles and watched a lot of videos. It is said that coroutines are useful for asynchronous programming. As an example it is usual demonstrated similar examples. Let's look to one of them: James McNellis "Introduction to C++ Coroutines" from CppCon2016 (Timing 1:40 - 6:00).
Imagine that we want to establish TCP connection and get data from TCP connection:
int64_t tcp_reader(int64_t total) {
std::array<char, 4096> buffer;
tcp::connection the_connection = tcp::connect("127.0.0.1", 1337);
int64_t remaining = total;
for (;;) {
int64_t bytes_read = the_connection.read(buffer.data(), buffer.size()).get();
remaining -= bytes_read;
if (remaining <= 0 || bytes_read == 0) { return remaining); }
}
}
It is not asynchronous, let's imagine that connect() and read() functions already asynchronous(returns std::future) and re-write the function in asynchronous way(too much typing, inserted a picture instead):

Hmmmmm. Looks crazy, let's rewrite it with coroutines:
// std::future instead of just int
std::future<int64_t> tcp_reader(int64_t total) {
std::array<char, 4096> buffer;
// tcp::connect returns std::future. Added co_await
tcp::connection the_connection = co_await tcp::connect("127.0.0.1", 1337);
int64_t remaining = total;
for (;;) {
// tcp::connect::read returns std::future. Added co_await
int64_t bytes_read = co_await the_connection.read(buffer.data(), buffer.size()).get();
remaining -= bytes_read;
if (remaining <= 0 || bytes_read == 0) { return remaining); }
}
}
I do not understand why we complicate it so much. I would just rewrite initial code like this:
int64_t tcp_reader(int64_t total) {
std::array<char, 4096> buffer;
// tcp::connect returns std::future. Add get();
tcp::connection the_connection = tcp::connect("127.0.0.1", 1337).get();
int64_t remaining = total;
for (;;) {
// tcp::connect::read returns std::future. Add get();
int64_t bytes_read = the_connection.read(buffer.data(), buffer.size()).get();
remaining -= bytes_read;
if (remaining <= 0 || bytes_read == 0) { return remaining); }
}
}
std::future<int64_t> async_tcp_reader(int64_t total) {
return std::async([total]{ tcp_reader(total); });
}
Simple and straightforward, isn't it?
I also looked to await/async examples in other languages(Python/JS), there are similar usages.
Is there are any advantages of using coroutines, comparably to my code in this example?
How coroutines can improve my asynchronous code? If you know, please, provide some examples that can illustrate the power of coroutines in async programming