
Christopher Kohlhoff wrote:
Hi Darryl,
Christopher Kohlhoff wrote:
For stream-oriented I/O, this separation is presented in the form of the Stream concept. This concept is implemented by stream_socket, ssl::stream, buffered_read_stream and so on. It would be implemented by a hypothetical pipe class.
Precisely. Why write it/maintain it again?
Well... because although the interface might be the same the implementation is different.
But in many cases it isn't. That was my point.
What do you mean by "default" - is the default selectable at design/implementation or compilation time?
By "default" I mean that the interface should be designed to use compile time polymorphism with concepts. Runtime polymorphism can be introduced, should the developer choose, through a wrapper.
Ok.
This adds up considerably if there are many layers of runtime polymorphism involved.
Can we cut the re-education program for java programmers :-) out of this and deal with the use case constructively, or would you prefer to ignore it?
My design choice is based on experience in developing real-world high-performance networking applications that are often CPU bound.
A previous system I worked on made extensive use of runtime polymorphism via the ACE_Streams abstraction, where passing data through each layer involves a virtual function call.
I don't recall suggesting building ACE. If anyone had I would have screamed loudly. I didn't ask for a traditional OO layered polymorphic monster - I just suggested that it was such a common use case to want to read/write to anything that supported read/write concepts that this should be supported. It isn't exactly unprecedented.
Since configuration of the individual layers did not need to occur at runtime, this runtime polymorphism was unnecessary. Removing it markedly improved performance.
Yep. Sounds familiar.
responding and gmane being my only interface at the time I hadn't seen Caleb's results when I posted).
I do not believe that particular test is representative of
Ok. Lets leave the optimization for a separate discussion based on tests etc.
You are now expressing concern about virtual function overhead
Double indirection is not the only cost of runtime polymorphism, [snip others] Do I have the benchmarks on hand to support this? No, but I have done these tests in the past. Working on high performance systems has taught me that runtime polymorphism has very real costs, and so in general should not be introduced unless runtime variation of behaviour is required. The design of asio reflects this experience.
I don't disagree with your concerns here, though it seems from my perspective that runtime polymorphism is being singled out as the root of all evil while other impl details can be at least as significant. Note I am only asking for runtime polymorphism to the extent that it is needed to support basic operations (read/write) not for some monstrous framework. My experience in memory + CPU constrained high performance systems using ACE led me to delete it and replace it with an in-house lib with rather selective (like 1) use of runtime polymorphism. YMMV. I'm done.
Short of placing a wrapper around asio to make it more
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Yes to the following - but there is an aspect of code re-use that it doesn't address.
Which aspect would this be?
I meant wrapping N identical impls in a polymorphic wrapper to make them interchangeable didn't improve code re-use, thats all.
stream_socket and ssl::stream. For example, both work equally well with free
template !
I guess this means that you like templates about as much as I like virtual functions. :)
You must be kidding. I've been writing code that VC6 can't compile since VC6 was released :-). C++ has a lot of features - I try to use them appropriately. The "template!" was in the context of my concern that I didn't want to have to template every piece of code that did any reading/writing using the lib - a template function doesn't help in that.
I would expect many systems would be able to share a lot of implementation across different stream-like file/socket/device interfaces at least.
I don't think there would be as much sharing as you might think
I'm only basing this on my experience - note I'm not expecting a huge difference in code size etc - I'm more interested in reliability and maintainability.
And even in cases where there is some sharing, the common functionality can be extracted into a function or class to be called from each place, so I don't see how this design necessarily leads to bloat.
Ok. Bloat wasn't fair - its not a huge amount of code, and the code can be extracted as you say. In one of my other posts I suggest doing that by making lower level policy/concept composition available for library extension etc.
Fundamentally, asio's public interface cannot assume sharing, since that assumption is already known to be incorrect.
Yes - thats where you need runtime polymorphism :-) If we can step back from the technique a little and take a look at usage, what I would like to see is some object that provides enough of the interface to allow stream read/write independent of the underlying stream. I would like a user that only required stream read to be able to use a read only stream such as the read end of a pipe. I would like that checking to occur at compile time. Similarly for write. While it is always possible to wrap a number of underlying objects with similar interfaces to introduce polymorphism, these conceptual base classes can't be injected as easily. This crosses over into the area of service composition as discussed in my reply re portability (and a little in demuxer). It would probably be more productive to let this specific thread die and concentrate on the portability one. Regards Darryl Green.