
"Christopher Kohlhoff" <chris@kohlhoff.com> wrote
Let me state as clearly as possible: the synchronous operations are not implemented in terms of the asynchronous operations. They call the underlying synchronous system call with little overhead.
OK.
So, the nub of your issue appears to be the conceptual difficulties you perceive in having the socket constructor take a demuxer, and for the interface to include both synchronous and asynchronous operations.
Right, I have a conceptual problem with having to allocate an object that is never used.
Let's consider the alternative approach proposed: to split the socket class into separate sync_socket and async_socket classes.
That's one way of doing things. The other might be to move read/write operations outside the socket class.
The drawbacks of this approach are increased redundancy and complexity in the programming interface. If this approach were already in place, I can imagine that I would be getting questions about why there are so many socket classes, and which one is the most appropriate to use.
There are trade-offs in every design decision. I elected to give synchronous and asynchronous operations equal weight, and combine them in a single interface. This has the added advantage of allowing mixed-mode programming, where synchronous operations can be used alongside asynchronous in a single application. As you point out, there are situations where synchronous is more appropriate, and these differences can occur within an application.
I don't think that the need to pass a demuxer to the socket constructor is conceptually difficult to explain. It's there for the asynchronous operations, if and when you need them.
My complain is not about explanation, but about a conceptual cleanness of the interface. One has to allocate an object which is not used, and this rings a bell.
I also do not agree that it is onerous to have to pass the demuxer to the constructor, or to pass it wherever it's needed in the program. You can make it a global, declare a new one for each use, or even use one associated with an existing object, as in:
stream_socket s(my_acceptor.demuxer());
Therefore I stand by my design choices as the best balance between usability, functionality and flexibility.
I respect that.
Now, to turn to more philosophical matters, namely synchronous versus asynchronous approaches.
As you pointed out, synchronous socket programming is easier to debug. However, there are also disadvantages, notably increased resource usage (with a thread required per connection)
I actually meant fixed amount of worker threads taking tasks from the queue -- not a thread per connection.
[...]
Regards, Arkadiy