On 30 Aug 2015 at 22:47, Thomas Heller wrote:
No, this stuff is at the core of where we are diverging in approach and why the AFIO API is so displeasing to you.
Where I am coming from is this:
"If the cost of defaulting to guaranteed memory safety to the end user is less than 0.5% overhead, I will default to guaranteed memory safety."
Where did you get this number from?
The benchmarks I ran before deciding on whether enforcing shared_ptr on handle was an acceptable overhead. You've got to understand Thomas you and your fellow HPC colleagues are attacking AFIO's "overhead" without having run any benchmarks. You're claiming all this poor performance and high overhead stuff having absolutely no idea of performance on the ground. As I much as I appreciate where you think you're coming from, the benchmarks I ran before deciding on a shared_ptr on every handle said it was an inconsequential overhead. That's why I chose that design.
I appreciate that from your perspective, it's a question of good design principles, and splashing shared_ptr all over the place is not considered good design. For the record, I *agree* where the overhead of a shared_ptr *could* be important - an *excellent* example of that case is std::future<T> which it is just plain stupid that those use memory allocation at all, and I have a non memory allocating implementation which proves it in Boost.Outcome. But for AFIO, where the cost of a shared_ptr will always be utterly irrelevant compared to the operation cost, this isn't an issue.
And it all starts to make sense ... since you have that memory allocation already for handle and friends, you seem to try to optimize it away in the future? As said earlier, your API functions should not operate on a future to a handle in any form.
I think you're missing the point. Futures get created and destroyed every single operation, so removing the memory allocation there is a big win. shared_ptr<handle> allocates once on handle create. You want to avoid ever opening files in high performance filesystem code anyway, it's always very slow. I'd even go so far as to say that there isn't much point in optimising handle creation given how slow the open() call is (which is still orders of magntitude faster than CreateHandle()).
I also have a second big reason I haven't mentioned until now for the enthusiasm for shared_ptr. In addition to needing to bind internal workaround objects to lifetimes of things, AFIO's dispatcher and handle will be bound into other languages such as .NET, C, Python etc. All these languages use reference counting as part of their garbage collection, and therefore if the lifetime of AFIO objects is also reference count managed it makes getting the interop in situations where say a Python interpreter is loaded into the local process much easier.
Then what's stopping you from implementing that for those layers? Why does *everyone* else has to pay for it? Again, this goes against the very principle "Don't pay for what you don't use".
It doesn't work that way Thomas. You'd need to go implement a SWIG wrapper and you'll see what I mean: lifetimes of C++ objects are intimitely tied into their foreign language wrappers. And as I keep repeating, the cost of a shared_ptr relative to a handle is immaterial.
I expect after the lightweight futures refactor of AFIO to add John Bandela's CppComponents support to AFIO. This lets you wrap AFIO objects into Microsoft COM objects, and from there rebinds into any other programming language is quite easy.
To be honest, I just don't care about that. While that might be a cool feature for some, why does everyone has to pay for that?
As you have probably noticed in this review, most of the Boost C++ community doesn't see a need for this library. This isn't the case elsewhere.
This is a BIG reason I am so absolute regarding ABI stability. Microsoft COM imposes stern requirements on the ABI layer. A big reason behind Monad is solving C++ exception transport through Microsoft COM, hence my predilection for APIs which are noexcept returning monad<T> as those are 100% Microsoft COM compatible.
Again, why does everyone has to pay for that?
Monad is pretty much zero relative overhead. Nobody is paying anything here.
How does this behave when having different CRTs?
I believe Bandela's CppComponents takes care of all that. You can mash up Mingw with MSVCRT if you like. It's totally encapsulated at the COM boundary.
I hope you understood by now that all those questions could have been avoided if you just reused what's already there.
What you're really saying here: "all these questions could have been avoided if you designed it the way I told you". Well, sure, of course. But as I've explained now, I think your design doesn't work well in practice. You think it will, but if you implement it you will find it won't deliver you any benefit for the cost. Asynchronous file system and file i/o is usually slower than synchronous - so you're looking for the value add, not the performance add.
Why isn't it possible that consumers of AFIO implement all those ABI stability stuff?
You don't appear to understand well how ABI stable C++ is designed. It requires imposing costs on everybody. Look at the PIMPL idiom.
It seems to be highly platform dependant anyway.
Bandela's CppComponents is entirely portable. Microsoft COM objects are very well understood and can be consumed by a very wide suite of software including all .NET languages.
I would like to settle this now as we are starting to running in circles. I understand your point of view you do mine. I think all has been said. We probably won't agree 100% with each other and that's fine for me.
I think we've reached that point as well. Thanks for your feedback Thomas. Yours was by far the most useful. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/