From b20a954592f672ffca2c45e9905b8d15e65b0b0a Mon Sep 17 00:00:00 2001 From: Hans Fugal Date: Thu, 26 Jun 2014 15:20:40 -0700 Subject: [PATCH] (wangle) s/continuation/callback Summary: The word "continuation" is too ambiguous. Prefer callback (except where we are actually talking about CSP continuations in the README). Test Plan: Still builds. Nothing external is or should be calling `setContinuation`. But I'll wait for contbuild anyway. Reviewed By: hannesr@fb.com Subscribers: net-systems@, fugalh, exa FB internal diff: D1406753 Tasks: 4480567 --- folly/wangle/Future-inl.h | 18 +++++++++--------- folly/wangle/Future.h | 2 +- folly/wangle/Later-inl.h | 2 +- folly/wangle/Later.h | 2 +- folly/wangle/README.md | 10 +++++----- folly/wangle/detail.h | 8 ++++---- folly/wangle/test/FutureTest.cpp | 10 +++++----- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/folly/wangle/Future-inl.h b/folly/wangle/Future-inl.h index 47bede0e..cc6b6bf0 100644 --- a/folly/wangle/Future-inl.h +++ b/folly/wangle/Future-inl.h @@ -45,7 +45,7 @@ Future& Future::operator=(Future&& other) { template Future::~Future() { if (obj_) { - setContinuation([](Try&&) {}); // detach + setCallback_([](Try&&) {}); // detach } } @@ -57,9 +57,9 @@ void Future::throwIfInvalid() const { template template -void Future::setContinuation(F&& func) { +void Future::setCallback_(F&& func) { throwIfInvalid(); - obj_->setContinuation(std::move(func)); + obj_->setCallback_(std::move(func)); obj_ = nullptr; } @@ -112,7 +112,7 @@ Future::then(F&& func) { in some circumstances, but I think it should be explicit not implicit in the destruction of the Future used to create it. */ - setContinuation( + setCallback_( [p, funcm](Try&& t) mutable { p->fulfil([&]() { return (*funcm)(std::move(t)); @@ -139,12 +139,12 @@ Future::then(F&& func) { // grab the Future now before we lose our handle on the Promise auto f = p->getFuture(); - setContinuation( + setCallback_( [p, funcm](Try&& t) mutable { try { auto f2 = (*funcm)(std::move(t)); // that didn't throw, now we can steal p - f2.setContinuation([p](Try&& b) mutable { + f2.setCallback_([p](Try&& b) mutable { p->fulfilTry(std::move(b)); }); } catch (...) { @@ -189,7 +189,7 @@ inline Future Future::via(Executor* executor) { folly::MoveWrapper> p; auto f = p->getFuture(); - setContinuation([executor, p](Try&& t) mutable { + setCallback_([executor, p](Try&& t) mutable { folly::MoveWrapper> tt(std::move(t)); executor->add([p, tt]() mutable { p->fulfilTry(std::move(*tt)); @@ -320,7 +320,7 @@ whenAll(InputIterator first, InputIterator last) for (size_t i = 0; first != last; ++first, ++i) { auto& f = *first; - f.setContinuation([ctx, i](Try&& t) { + f.setCallback_([ctx, i](Try&& t) { ctx->results[i] = std::move(t); if (++ctx->count == ctx->total) { ctx->p.setValue(std::move(ctx->results)); @@ -347,7 +347,7 @@ whenAny(InputIterator first, InputIterator last) { for (size_t i = 0; first != last; first++, i++) { auto& f = *first; - f.setContinuation([i, ctx](Try&& t) { + f.setCallback_([i, ctx](Try&& t) { if (!ctx->done.exchange(true)) { ctx->p.setValue(std::make_pair(i, std::move(t))); } diff --git a/folly/wangle/Future.h b/folly/wangle/Future.h index 5390705d..b54b7c19 100644 --- a/folly/wangle/Future.h +++ b/folly/wangle/Future.h @@ -181,7 +181,7 @@ class Future { /// not worth listing all those and their fancy template signatures as /// friends. But it's not for public consumption. template - void setContinuation(F&& func); + void setCallback_(F&& func); private: typedef detail::FutureObject* objPtr; diff --git a/folly/wangle/Later-inl.h b/folly/wangle/Later-inl.h index 4f00e268..d1e1ef88 100644 --- a/folly/wangle/Later-inl.h +++ b/folly/wangle/Later-inl.h @@ -134,7 +134,7 @@ Later Later::via(Executor* executor) { Later later(std::move(starter_)); later.future_ = promise->getFuture(); - future_->setContinuation([executor, promise](Try&& t) mutable { + future_->setCallback_([executor, promise](Try&& t) mutable { folly::MoveWrapper> tt(std::move(t)); executor->add([promise, tt]() mutable { promise->fulfilTry(std::move(*tt)); diff --git a/folly/wangle/Later.h b/folly/wangle/Later.h index 0f58ff3c..c37e698a 100644 --- a/folly/wangle/Later.h +++ b/folly/wangle/Later.h @@ -28,7 +28,7 @@ template struct isLater; /* * Since wangle primitives (promise/future) are not thread safe, it is difficult * to build complex asynchronous workflows. A Later allows you to build such a - * workflow before actually launching it so that continuations can be set in a + * workflow before actually launching it so that callbacks can be set in a * threadsafe manner. * * The interface to add additional work is the same as future: a then() method diff --git a/folly/wangle/README.md b/folly/wangle/README.md index 4b793330..b97a7272 100644 --- a/folly/wangle/README.md +++ b/folly/wangle/README.md @@ -13,7 +13,7 @@ A framework for expressing asynchronous control flow in C++, that is composable Wangle is a futures-based async framework inspired by [Twitter's Finagle](http://twitter.github.io/finagle/) (which is in scala), and (loosely) building upon the existing (but anemic) Futures code found in the C++11 standard ([`std::future`](http://en.cppreference.com/w/cpp/thread/future)) and [`boost::future`](http://www.boost.org/doc/libs/1_53_0/boost/thread/future.hpp) (especially >= 1.53.0). Although inspired by the std::future interface, it is not syntactically drop-in compatible because some ideas didn't translate well enough and we decided to break from the API. But semantically, it should be straightforward to translate from existing std::future code to Wangle. -The primary semantic differences are that Wangle Futures and Promises are not threadsafe; and as does `boost::future`, Wangle supports continuations (`then()`) and there are helper methods `whenAll()` and `whenAny()` which are important compositional building blocks. +The primary semantic differences are that Wangle Futures and Promises are not threadsafe; and as does `boost::future`, Wangle supports continuing callbacks (`then()`) and there are helper methods `whenAll()` and `whenAny()` which are important compositional building blocks. ## Brief Synopsis @@ -139,7 +139,7 @@ auto any = whenAny(futs.begin(), futs.end()); `all` and `any` are Futures (for the exact type and usage see the header files). They will be complete when all/one of `futs` are complete, respectively. (There is also `whenN()` for when you need *some*.) -Second, we can attach continuations (aka callbacks) to a Future, and chain them together monadically. An example will clarify: +Second, we can attach callbacks to a Future, and chain them together monadically. An example will clarify: ```C++ Future fut1 = mc.get("foo"); @@ -163,7 +163,7 @@ Future fut3 = fut2.then( That example is a little contrived but the idea is that you can transform a result from one type to another, potentially in a chain, and unhandled errors propagate. Of course, the intermediate variables are optional. `Try` is the object wrapper that supports both value and exception. -Using `then` to add continuations is idiomatic. It brings all the code into one place, which avoids callback hell. +Using `then` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell. Up to this point we have skirted around the matter of waiting for Futures. You may never need to wait for a Future, because your code is event-driven and all follow-up action happens in a then-block. But if want to have a batch workflow, where you initiate a batch of asynchronous operations and then wait for them all to finish at a synchronization point, then you will want to wait for a Future. @@ -266,7 +266,7 @@ p.fulfil([]{ ## FAQ ### Why not use std::future? -No callback or continuation support. +No callback support. See also http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf ### Why not use boost::future? @@ -278,7 +278,7 @@ See also http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf C++. It boils down to wanting to return a Future by value for performance (move semantics and compiler optimizations), and programmer sanity, and needing a reference to the shared state by both the user (which holds the Future) and the asynchronous operation (which holds the Promise), and allowing either to go out of scope. ### What about proper continuations? Futures suck. -People mean two things here, they either mean using continuations or they mean using generators which require continuations. It's important to know those are two distinct questions, but in our context the answer is the same because continuations are a prerequisite for generators. +People mean two things here, they either mean using continuations (as in CSP) or they mean using generators which require continuations. It's important to know those are two distinct questions, but in our context the answer is the same because continuations are a prerequisite for generators. C++ doesn't directly support continuations very well. But there are some ways to do them in C/C++ that rely on some rather low-level facilities like `setjmp` and `longjmp` (among others). So yes, they are possible (cf. [Mordor](https://github.com/ccutrer/mordor)). diff --git a/folly/wangle/detail.h b/folly/wangle/detail.h index 8a89c641..105ebc3a 100644 --- a/folly/wangle/detail.h +++ b/folly/wangle/detail.h @@ -46,9 +46,9 @@ class FutureObject { } template - void setContinuation(F func) { + void setCallback_(F func) { if (continuation_) { - throw std::logic_error("setContinuation called twice"); + throw std::logic_error("setCallback_ called twice"); } continuation_ = std::move(func); @@ -111,7 +111,7 @@ struct VariadicContext { template typename std::enable_if::type whenAllVariadicHelper(VariadicContext *ctx, THead&& head, Fs&&... tail) { - head.setContinuation([ctx](Try&& t) { + head.setCallback_([ctx](Try&& t) { std::get(ctx->results) = std::move(t); if (++ctx->count == ctx->total) { ctx->p.setValue(std::move(ctx->results)); @@ -123,7 +123,7 @@ whenAllVariadicHelper(VariadicContext *ctx, THead&& head, Fs&&... tail) { template typename std::enable_if::type whenAllVariadicHelper(VariadicContext *ctx, THead&& head, Fs&&... tail) { - head.setContinuation([ctx](Try&& t) { + head.setCallback_([ctx](Try&& t) { std::get(ctx->results) = std::move(t); if (++ctx->count == ctx->total) { ctx->p.setValue(std::move(ctx->results)); diff --git a/folly/wangle/test/FutureTest.cpp b/folly/wangle/test/FutureTest.cpp index bc6f209b..df99aebb 100644 --- a/folly/wangle/test/FutureTest.cpp +++ b/folly/wangle/test/FutureTest.cpp @@ -279,18 +279,18 @@ TEST(Future, finish) { Promise p; auto f = p.getFuture().then([x](Try&& t) { *x = t.value(); }); - // The continuation hasn't executed + // The callback hasn't executed EXPECT_EQ(0, *x); - // The continuation has a reference to x + // The callback has a reference to x EXPECT_EQ(2, x.use_count()); p.setValue(42); - // the continuation has executed + // the callback has executed EXPECT_EQ(42, *x); - // the continuation has been destructed + // the callback has been destructed // and has released its reference to x EXPECT_EQ(1, x.use_count()); } @@ -676,7 +676,7 @@ TEST(Future, waitWithSemaphore) { EXPECT_EQ(result.load(), 1); p.setValue(42); t.join(); - // validate that the continuation ended up executing in this thread, which + // validate that the callback ended up executing in this thread, which // is more to ensure that this test actually tests what it should EXPECT_EQ(id, std::this_thread::get_id()); EXPECT_EQ(result.load(), 42); -- 2.34.1