On Fri, Mar 15, 2019 at 7:19 AM Stian Zeljko Vrba <vrba@quine.no> wrote:

> I believe it is wrong to blame Asio for this.


I disagree. Recently, I've been coding parallel, including networked & asynchronous, programs in C# and Java, and the experience has been a JOY. You get threads, executors, synchronization primitives, tasks, cancellation, monadic futures and concurrent (blocking and non-blocking) data structures out of the box with the platform, plus a myriad of extensions as libraries. As for executors, you don't need to be bothered with them unless you really want to for some reason.

If you were to compare POSIX or BSD sockets to C# and Java, you would say exactly the same things. Asio (like Beast) is a low-level, portable abstraction of I/O. You can BUILD "threads", "executors", "synchronization primitives", "tasks", "cancellation", "monadic futures", and "concurrent data structures" with it. Does this mean OS-level sockets are the wrong abstraction?

Of course not. The reason C# seems "ahead" of C++ is two-fold:

1. WG21 goofed up by delaying networking
2. C# is not developed through the International Standards Process

These mistakes are being fixed though, and you will see library support in C++ catch up by leaps and bounds. And when we finally get these things (built on top of Asio/Networking TS, which has proven over and over to be the correct low-level abstraction) it will be better than C#, Java, or Rust.


Compare the documentation for Vertx (vertx.io) or netty (both Java toolkits for writing asynchronous reactive programs) with that of asio.

Yes I agree, there is a lack of documentation and especially tutorials for beginners (which I am trying to fix). This has nothing to do with whether Asio is the right portable, low-level abstraction (it is) but the lack of guidance from the author could lead you to believe incorrect things about the lib.

Once I attempted to write an asio service, tried to understand the simple example from the documentation, and I gave up. I used a thread, blocking call and CancelSynchronousIO (and I consider myself fortunate to develop for Windows only that has it).

The documentation on services is particularly scant. There is no explanation of what they are for, how to use them, best practices, or even "Frequently Asked Questions." I was able to figure it out though, but I am able to focus all of my time on it.
 
Asio _is_ a relatively nice wrapper around socket and serial port APIs, but that's about it

Yes now you're getting close to an accurate description. More correct would be to say that Asio provides robust abstractions of buffers, dynamic buffers, synchronous I/O, and asynchronous I/O. Networking is a subset of that (but not the only part, see signals and serial ports, and soon file I/O).
 
IMO. On the other hand, I could have written the same wrappers around native APIs in two days and not haul along what I consider the baggage of technical debt that is asio in the codebase.

There is no API technical debt. That is to say, that the interfaces are modern and up-to-date. You could argue that particular implementations such as Boost.Asio have extra code to provide C++03 compatibility, but this has nothing to do with the soundness of the design. As these interfaces are part of a TS, there will be implementations in gcc and clang appearing shortly (if not already so). These will be written from scratch so there will be no support for older C++.
 
Conclusion, if any: many people just want/need thread per client and synchronous IO for simplicity, but until asio/networking TS provide for timeouts and cancellation of synchronous requests, it's a wrong tool for those people, me included.

If you define

struct sync_socket
{
  net::io_context ioc_;
  net::ip::tcp::socket_;
  net::steady_timer timer_;
  ...
  template<class Buffers>
  std::size_t write_some (Buffers const& b);
};

You can easily implement timeouts in `write_some` thusly:

template<class Buffers>
std::size_t
sync_socket::
write_some (Buffers const& b, error_code& ec)
{
  std::size_t n;
  timer_.expires_after(seconds(30));
  timer_.async_wait(
    [&](error_code ec)
    {
      socket_.cancel(ec):
    });
  socket_.async_write_some(b,
    [&](error_code ec_, std::size_t n_)
    {
      ec = ec_; n = n_;
    });
    ioc_.run();
    return n;
}

Now, you can use `sync_socket` with all the usual sync write operations like `net::write`, and get timeouts.

Thanks