Boost logo

Boost :

From: Braddock Gaskill (braddock_at_[hidden])
Date: 2008-04-13 18:33:09


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'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.

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.
-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).
-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.
--
2) Second - Lazy Futures.  
This is something I picked up from the Oz language future implementation, and
have found very useful.  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.
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).
Braddock Gaskill

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk