void foo(int x) { // do something with x cout << "foo(" << x << ")" << endl; }
// ...
cout << "making Promise" << endl; Promise<int> p; Future<int> f = p.getFuture(); f.then(foo); cout << "Future chain made" << endl;
// ... now perhaps in another event callback
cout << "fulfilling Promise" << endl; p.setValue(42); cout << "Promise fulfilled" << endl;
<span class="n">Result</span> <span class="n">result</span><span class="p">;</span> <span class="c1">// The value when result is FOUND,</span> <span class="c1">// The error message when result is SERVER_ERROR or CLIENT_ERROR</span> <span class="c1">// undefined otherwise</span> <span class="n">string</span> <span class="n">value</span><span class="p">;</span>
};
GetReply get(string key); };
vector<Future<GetReply>> futs; for (auto& key : keys) { futs.push_back(mc.get(key)); } auto any = collectAny(futs.begin(), futs.end());
Future<string> fut2 = fut1.then( [](GetReply reply) { if (reply.result == MemcacheClient::GetReply::Result::FOUND) return reply.value; throw SomeException("No value"); });
Future<Unit> fut3 = fut2 .then([](string str) { cout << str << endl; }) .onError([](std::exception const& e) { cerr << e.what() << endl; });
// Thread B f.then(x).then(y).then(z);
// Thread A p.setValue();
f.isReady() == false
p.setValue(42);
f.isReady() == true f.value() == 42
f.isReady() == false
p.setException(std::runtime_error("Fail"));
f.isReady() == true f.value() // throws the exception
f.then([](int i){ cout << i; });
p.setValue(42);
f2.then([](string s){ /* ... */ });
f2.then([](Try<string> const& s){ ... });
struct Foo { void memberMethod(Try<int> const& t); static void staticMemberMethod(Try<int> const& t); }; Foo foo;
// bind global function makeFuture<int>(1).then(globalFunction); // bind member method makeFuture<int>(2).then(&Foo::memberMethod, &foo); // bind static member method makeFuture<int>(3).then(&Foo::staticMemberMethod);
Future<int> foo(int arg) { auto promise = std::make_shared<Promise<int>>();
fooOldFashioned(arg, [promise](int result) { promise->setValue(result); });
return promise->getFuture(); }
Promise<int> p1, p2, p3; p1.setException(std::runtime_error("oh no!")); p2.setException(folly::make_exception_wrapper<std::runtime_error>("oh no!")); p3.setException(std::current_exception());
// Try is also integrated with exception_wrapper makeFuture<int>(std::runtime_error("ugh")).then([](Try<int> t){ if (t.hasException<std::exception>()) { // this is enough if we only care whether the given exception is present } });
makeFuture<int>(std::runtime_error("ugh")).then([](Try<int> t){ // we can also extract and handle the exception object // TODO(jsedgwick) infer exception type from the type of the function bool caught = t.withException<std::exception>([](const std::exception& e){ // do something with e }); });
// f now contains the result of the then() callback, unless the ensure() // callback threw, in which case f will contain that exception
std::vector<Future<T>> fs; for (int i = 0; i < 10; i++) { fs.push_back(someRPC(i)); }
collectAll(fs).then([](const std::vector<Try<T>>& tries){ for (const auto& t : tries) { // handle each response } });
// Or using a Try: collect(fs).then([](const Try<std::vector<T>>& t) { // ... });
// Thread B f.then(x).then(y);
// Thread A p.setValue();
// f will complete with a TimedOut exception if the Future returned by foo() // does not complete within 500 ms f = foo().within(milliseconds(500));
// Same deal, but a timeout will trigger the provided exception instead f2 = foo().within(milliseconds(500), std::runtime_error("you took too long!"));
// If the Future doesn't complete within one second, f will remain // incomplete. That is, if a timeout occurs, it's as if wait() was // never called. Future<int> f = foo().wait(milliseconds(1000));
// Or maybe we want the Future to complete with some special value p.setValue(42);
// Or maybe we don't want to do anything at all! Including not setting // this handler in the first place. });
auto f = p.getFuture(); // The Future holder can now send an interrupt whenever it wants via raise(). // If the interrupt beats out the fulfillment of the Promise and there is // an interrupt handler set on the Promise, that handler will be called with // the provided exception f.raise(std::runtime_error("Something went awry! Abort!"));
// cancel() is syntactic sugar for raise(FutureCancellation()) f.cancel();
// The mock implementation class MockAsyncClient : public AsyncClient { public: // Declare a mock method foo_ that takes an int and returns an int MOCK_METHOD1(foo_, int(int));
// Plug the mock into an override of the interface Future<int> foo(int i) override { // Lift the result back into a Future before returning return makeFuture<int>(foo_(i)); } };
// Let's say that we're testing a class MyProxy that simply forwards foo() // calls to AsyncClient and returns the result class MyProxy { public: Future<int> foo(int i) { return client->foo(i); } void setClient(AsyncClient client); private: AsyncClient client; };
// Now, in our testing code MyProxy proxy; MockAsyncClient mockClient; // Inject the mock proxy.setClient(&mockClient) // Set an expectation on the mock to be called with 42 and return 84 EXPECT_CALL(mockClient, foo_(42)).WillOnce(Return(84)); // Trigger the call auto f = MyProxy.foo(42); // If everything has been mocked out synchronously, we can just check the // value of the future directly EXPECT_EQ(84, f.value());PitfallsEventBase, EventBaseManager, Executor #
-- "bind" is a function that takes a monad, and a function that takes a value -- and returns another monad. Haskellers call this ">>=" because they are -- vying to unseat perl from the throne of illegibility. bind :: m a -> (a -> m b) -> m b
// "then" is "bind" template <class B> Future<B> then(std::function<Future<B>(A));
... };
// "makeFuture" is also "unit", and we will need it because constructors can't // really be converted to std::function (AFAIK) template <class A> Future<A> makeFuture(A);
// Right Identity Future<A> m; m.then(makeFuture<A>) == m
// Associativity Future<A> m; std::function<Future<B>(A)> f; std::function<Future<C>(B)> g; m.then(f).then(g) == m.then([](A x) { return f(x).then(g); })
-- Left Identity unit >=> g ≡ g -- Right Identity f >=> unit ≡ f -- Associativity (f >=> g) >=> h ≡ f >=> (g >=> h)