Subject: Re: [boost] [afio] Formal review of Boost.AFIO
From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2015-08-27 23:08:14
> On 28/08/2015 00:58, Hartmut Kaiser wrote:
> > Third, the terminology 'consuming' and 'non-consuming' future does not
> > any sense (to me). More importantly it is by no means Standard-
> terminology -
> > thus reasoning in terms of those makes it much more difficult for us to
> > about the same thing.
> future.get() moves the result of the promise from the internal state,
> thereby consuming it. Further calls to get() or then() fail.
> shared_future.get() copies the result of the promise from the internal
> state, thereby not consuming it. Further calls to get() or then()
All of this is an irrelevant implementation detail. Nobody forces the future
to share its state with a promise. It could very well be a packaged_task,
for instance, or any other asynchronous provider.
> I find it hard to imagine this being a difficult concept.
> > I don't see a reason why anybody would do this. If you know (as a user)
> > need shared ownership you just make it explicit by assigning the
> > boost::future to a boost::shared_future (as you showed in Example A).
> His point was that someone might forget and then it becomes a runtime
> exception, which can be painful to find if it's in a seldom-executed
> part of the code (perhaps error handling).
If somebody forgets, then an exception is the correct thing to do.
Alternatively an assertion could be used in this case as well.
BTW, an exception is not difficult to find, even gdb can break on a specific
exception being thrown.
> >> future h=async_file("niall.txt");
> >> shared_future h2(h);
> >> // Call these continuations when h becomes ready
> >> for(size_t n=0; n<100; n++)
> >> // Each of these initiates an async read, so queue depth = 100
> >> h2.then(detail::async_read(buffer[n], 1, n*4096));
> > Sure, but Example A is just fine, as said.
> Note that it's not user code calling then() on the futures in most cases
> -- see the examples. Instead the future is passed as a "precondition"
> parameter to a wrapper API in the library, which is what actually
> registers the continuation.
> I think Niall's point is that it's harder for the wrapper to know
> whether it's going to be called a single time or multiple times for a
> given precondition future, so it's safest if that is accepted only as a
> BUT that means that there is absolutely no benefit (and some drawbacks)
> to returning non-shared futures, as a result (there are only potentially
> some savings if they're never used as preconditions).
> I suppose arguably the wrappers could be templated to accept either
> future or shared_future, which might mitigate that. But perhaps there
> are reasons why that's undesirable as well.
If an API enforces wrong behavior, then the API itself is wrong.
Thus, if the wrappers require for the code to return a shared_future, then
the wrappers are wrong in the first place. They force the user to deal with
library internals which are irrelevant and misleading.