What are senders good for, anyway?
ericniebler.com
ericniebler.com
IMHO the more abstract and complex a system is, the more chances that something will go wrong. When one has to figure out what's actually happening among a huge mess of overly-abstracted code, simple and straightforward always wins. Perhaps it's some kind of job security.
Plus with a known interface between the code completing the work and the code wanting the result of the work gives you a much clearer boundary rather than having to keep all of the specific async model underlying it in your head (you'll still need -some- of it while debugging, sure, but much less).
So while your view about over-abstraction is often on point, I think in this case people will find that in practice it's no harder - and in some cases easier - to debug code written to the proposed standard.
I have had to drag people kicking and screaming into the Future before now, but in the end they've all thanked me.
https://github.com/bsideup/jabel
This is useful commercially, but also nice when building Minecraft mods for older versions of Minecraft.
In any case, Eric Niebler now works at NVidia, which has expressed an interest on Senders/Receivers as they are not just for networking, but a general mechanism for composition of async operations.
I still have my concerns, as I think the heavily templating will come at a cost of clarity, but I haven't tried them on a large application yet.
It turns out those long complex pieces of code are not something the consumer, the program writer, me and you, will ever need to see. If the author reads this, I apologise for saying so, but IMO the blog post aims well but misfires: it needs to communicate to C++ developers what code _they_, ie _us_ normal folk, will see and write. Otherwise we'll get scared off. (But, I do note your absolute enthusiasm shines through and that carried me through the entire post :))
> At this point you may be wondering what’s the point to all of this. Senders and receivers, operation states with fiddly lifetime requirements, connect, start, three different callbacks — who wants to manage all of this? The C API was way simpler. It’s true! So why am I so unreasonably excited about all of this? The caller of async_read_file doesn’t need to care about any of that.
This is in "step 6", about ten screens into the blogpost. Good thing I read the whole thing!
So, THIS is the takeaway. You have old code (C-style, like the Win32 API):
/// Old-style async C API with a callback
/// (like Win32's ReadFileEx)
struct overlapped {
// ...OS internals here...
};
using overlapped_callback =
void(int status, int bytes, overlapped* user);
int read_file(FILE*, char* buffer, int bytes,
overlapped* user, overlapped_callback* cb);
and this transforms into new C++ code: exec::task< std::string > process_file( FILE* pfile )
{
std::string str;
str.resize( MAX_BUFFER );
auto [bytes, buff] =
co_await async_read_file(pfile, str.data(), str.size());
str.resize( bytes );
co_return str;
}
Plus the additional money quote:> You want to use senders because then you can stitch your async operations together with other operations from other libraries using generic algorithms from still other libraries. And so you can co_await your async operations in coroutines without having to write an additional line of code.
> Why do we need senders when C++ has coroutines? [...] this isn’t an either/or. Senders are part of the coroutine story.
And actually -- that looks pretty good to me!
And if the author reads this, if I may suggest, put this first! (Combined with the note about multiple different APIs all made cohesive, give two examples perhaps.) But sell the solution, then explain the intricate mechanism.
And, great work. I can see myself writing code using this. I like it.
Asio also has its flaws, but the async story in C++ has quite the cognitive overload.
I saw that that happened but didn't have time to dig into it. Asio has been in use for a couple of decades so was surprised it didn't pass muster. Could anyone summarize what went wrong?
Admittedly what Nebler is talking about does look a lot simpler, but is it a reasonably full replacement for the functionality of Asio?
Still for what I have seen, sender/receiver only deal with composing async operations, the proposal so far still lack an actual network executor, so it is far from being ready.
This is a shame I think, because while asio might not have been perfect it means that in 2024 C++ still lacks a network library.