
----- Original Message ----- From: "Braddock Gaskill" <braddock@braddock.com> To: <boost@lists.boost.org> Sent: Monday, April 14, 2008 12:33 AM Subject: Re: [boost] Review Request: future library (Gaskill version)
On Thu, 10 Apr 2008 21:53:33 +0200, vicente.botet wrote:
How do your library positions with respect to the standard proposals? N2561 Anthony Williams: An Asynchronous Future Value
I've now taken a good look at the recent C++0X N2561 "An Asynchronous Future Value" proposal.
Both my library and N2561 are heavily based on Peter Dimov's earlier API... I dare say a few method name changes would make N2561 a proper subset of my future and promise classes and future_wrapper helper.
I thought that the future and promise separation was proposed by Christopher Kohlhoff http://www.nabble.com/-futures--composite-or-to9069443.html#a9473680 :) I think that you should add the reference to his post.
I'm disregarding the future C++ move semantics, of course. We need a future<C++0x>::wait() for that... :)
unique_future<T> is an interesting concept. Still wrapping my head around that.
Me too. There is still the packaged_task class. What do you think about?
My base classes offer two features which N2561 does not (and which I would really hope to see in any C++0X standard).
-- 1) First - future<T>::add_callback(f).
add_callback is a hook called when the future is fulfilled. End users probably shouldn't have to touch it, but framework authors (who write schedulers, asio, co-routines, etc) will DEFINITELY need it.
add_callback() enables the following:
-Future Operators ((f1 && f2) || (f3 && f2) etc) - With add_callback, custom future_operators can be written by users.
From the new documentation these operators are already provided by your library. I don't like too much the overloading of the && and || operators when they don't have logical semantics, but this is only a question of style and taste. maybe & and | are less controversal. And find very strange the function op()
-Guarded Schedulers (See my library doc "Future Concept Tutorial" section at http://braddock.com/~braddock/future) - Guards are a fundamental concept in the academic future languages I've studied (see some of Ian Foster's papers on Strand and PCN, for example). I have found you can do some amazing things with a guarded task scheduler (I've implemented one outside the future lib).
I like this usage of guards. Interesting. Could you add the reference in the documentation? I'll take a look.
-Basic "future fulfillment" event notification (ie, just use add_callback as an event handler). Gives you essentially a signals/slot capability. Not a fan.
An alternative to add_callback() would be to provide just the operators themselves - Guards can reasonably be derived from the combination ops.
Any of these mechanisms solve the busy wait in the N2561 motivating example.
I have not found the use of wait in the example ...
-- 2) Second - Lazy Futures.
This is something I picked up from the Oz language future implementation, and have found very useful. Could you add the referece. A Lazy Future essentially flags itself when it is "needed" - ie, when someone is blocked on a f.wait(), and f.get(), or has explicitly called "f.set_is_needed()". This allows, for example, a task to only process _IF_ the result is actually needed.
Again, see my library doc Tutorial where I show how to easily create a "Lazy Job Queue". Permits nice Memoization patterns as well.
Lazy Futures are also needed for "Lazy Future Streams". A Stream is the primary means of inter-task communication in future-related academic languages. It permits producer/consumer patterns and one-to-many channels. A Lazy stream allows the producer task to produce new items only as fast as his fastest consumer needs them (See Ian T. Foster's work again - or my test_future.hpp unit test code).
Note I provide an easy-to-use future stream library with std iterator interface.
I also provide a future::cancel(), which has been discussed in the other posts and which I'm not terribly attached to.
IMO, the fact cancel can not really ensure the function is stopped makes this operation not very safe. But maybe useful in some cases ...
I really like seeing the N2561 C++ proposal uses a split future/promise. Broken_promise exceptions have saved me many times in real-world applications. And I like that you aren't using the implicit type conversion (which has bitten me many times in real-world applications! I only use my future::get() method now).
(I still provide implicit conversion, but would take it out very fast if others are no longer attached to it).
I have just a question why there are three ways to get the value from a future. f, f() and f.get()? I don't like too much the implicit conversion. N2561 has removed the implicit conversion only from the unique_future but preserved it for shared_future. Can some one explain why? template <> class unique_future<void> { public: // ... void move(); // <<<<<<<<< // ... }; template <typename R> class shared_future { public: // ... // retrieving the value operator R const & () const; // <<<<<<<<< R const & get() const; // ... }; If this implicit conversion is definitively removed, the operators || and && will not need any more the op function wich is quite odd. Best _____________________ Vicente Juan Botet Escriba