From: Darryl Green (darryl.green_at_[hidden])
Date: 2005-12-28 21:38:21
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
>>>This adds up
>>>considerably if there are many layers of runtime
>>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
> 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.
> 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
>>You are now expressing concern about virtual function overhead
> Double indirection is not the only cost of runtime polymorphism,
> 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.
>>>>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
> 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.
>>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
> 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
> 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.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk