
Braddock Gaskill wrote:
These operators should create a new (composite)future, exposing the same interface as the (simple) futures you're composing. This composite future should handle the exceptions in a similar way as the embedded ones, i.e. propagate the exceptions catched in the embedded futures to the caller, as appropriate.
So, that would mean that for f3 = f1 || f2, if f1 propagates an exception while f2 succeeds, f3 still propagates an exception?
I think this is very much use case dependent and anything you code into a library for good will hurt somebody else. So my best guess here is to implement a policy based behavior, allowing to custimize exception handling and propagation.
Also, does your implementation of operator|| allow for constructs like f1 || f2 || f3 ?
I don't have a real implementation of composition, I posted that simple operator|| example out to show that it can be done without any changes operator|| to the base future<T>/promise<T> implementation, so that they can proceed more or less independently. I'm hoping we can make use of an existing composition implemenation.
The implementation of composition in the future's lib in the vault could be used as a starting point, however from todays POV I'ld prefer to reimplement it using Eric Nieblers excellent proto library. This simplifies the required meta template magic considerably.
As I understand it, the point you riase is if you want f1 || f2 || f3 to have the semantics of returning a future<variant<T1, T2, T3> > without modifiation to the base future class. I would think that could be done if operator||(future<T1>, future<T2) actually returns a proxy class which operator||is implicitly convertible to a future, and properly specialized operator|| functions are provided. I haven't given this much thought yet though.
But that raises another point with the variant/tuple semantics...if I do f3 = f1 || f2; f3 would then have the type future<variant<f1::type, f2::type> >. If I then do a seperate f5 = f3 || f4;
then does f5 have the type future<variant<f1::type, f2::type, f4::type> >, or future<variant<variant<f1:type, f2::type>, f4::type> >?
As long as you have variants only you can flatten the structure: future<variant<f1::type, f2::type, f4::type> > But as soon as you start combining || and && this isn't always possible anymore. Additional optimization can be done, if all futures in a operator|| sequence return the same type, in which case you don't need to use a variant.
Should there be a seperate future_group concept to disambiguate?
What do you mean by that?
Composition overloading with || or && gets very hairy or impossible if the current proposal to have a future implicitly convertable to it's value, with blocking, goes through. Maybe Peter has thoughts on this.
I personally don't like the idea of having the future convert implicitely to its value type at all. I'm not sure if this can be implemented completely fail proof without ruunning in surprising behavior.
I like the tuples/variant idea of composition, but how do you handle exceptions?
As I said, you might need to use policies allowing for the user to specify what to do with exceptions.
The semantics of composition still seems far less settled than the basic future concept, at least in my mind. Any references are appreciated, I have seen very few. I would like to discuss it.
Regards Hartmut