Commit 9f748fb5 authored by Marshall Cline's avatar Marshall Cline Committed by Facebook Github Bot

rvalueification of Future::onError(...): 1/n

Summary:
This is part of "the great r-valuification of folly::Future":
* This is something we should do for safety in general.
* Several of folly::Future's methods are lvalue-qualified even though they act as though they are rvalue-qualified, that is, they provide a postcondition that says, in effect, callers should act as though the method invalidated its `this` object (regardless of whether that invalidation was actual or logical).
* This violates the C++ principle to "Express ideas directly in code" (see Core Guidelines), and generally makes it more confusing for callers as well as hiding the actual semantics from tools (linters, compilers, etc.).
* This dichotomy and confusion has manifested itself by some failures around D7840699 since lvalue-qualification hides that operation's move-out semantics - leads to some use of future operations that are really not correct, but are not obviously incorrect.
* The goal of rvalueification is to make sure methods that are logically rvalue-qualified are actually rvalue-qualified, which forces callsites to acknowledge that rvalueification, e.g., `std::move(f).onError(...)` instead of `f.onError(...)`. This syntactic change in the callsites forces callers to acknowledge the method's rvalue semantics.

Reviewed By: LeeHowes

Differential Revision: D9441271

fbshipit-source-id: c65614a5529bf50bb9a209e3941d20f3688f2a80
parent 79f4a50c
...@@ -1138,7 +1138,7 @@ typename std::enable_if< ...@@ -1138,7 +1138,7 @@ typename std::enable_if<
!is_invocable<F, exception_wrapper>::value && !is_invocable<F, exception_wrapper>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value, !futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
Future<T>::onError(F&& func) { Future<T>::onError(F&& func) && {
typedef std::remove_reference_t< typedef std::remove_reference_t<
typename futures::detail::Extract<F>::FirstArg> typename futures::detail::Extract<F>::FirstArg>
Exn; Exn;
...@@ -1173,7 +1173,7 @@ typename std::enable_if< ...@@ -1173,7 +1173,7 @@ typename std::enable_if<
!is_invocable<F, exception_wrapper>::value && !is_invocable<F, exception_wrapper>::value &&
futures::detail::Extract<F>::ReturnsFuture::value, futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
Future<T>::onError(F&& func) { Future<T>::onError(F&& func) && {
static_assert( static_assert(
std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>:: std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
value, value,
...@@ -1233,7 +1233,7 @@ typename std::enable_if< ...@@ -1233,7 +1233,7 @@ typename std::enable_if<
is_invocable<F, exception_wrapper>::value && is_invocable<F, exception_wrapper>::value &&
futures::detail::Extract<F>::ReturnsFuture::value, futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
Future<T>::onError(F&& func) { Future<T>::onError(F&& func) && {
static_assert( static_assert(
std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>:: std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
value, value,
...@@ -1271,7 +1271,7 @@ typename std::enable_if< ...@@ -1271,7 +1271,7 @@ typename std::enable_if<
is_invocable<F, exception_wrapper>::value && is_invocable<F, exception_wrapper>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value, !futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
Future<T>::onError(F&& func) { Future<T>::onError(F&& func) && {
static_assert( static_assert(
std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>:: std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
value, value,
......
...@@ -1420,7 +1420,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1420,7 +1420,7 @@ class Future : private futures::detail::FutureBase<T> {
!is_invocable<F, exception_wrapper>::value && !is_invocable<F, exception_wrapper>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value, !futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
onError(F&& func); onError(F&& func) &&;
/// Overload of onError where the error continuation returns a Future<T> /// Overload of onError where the error continuation returns a Future<T>
/// ///
...@@ -1438,7 +1438,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1438,7 +1438,7 @@ class Future : private futures::detail::FutureBase<T> {
!is_invocable<F, exception_wrapper>::value && !is_invocable<F, exception_wrapper>::value &&
futures::detail::Extract<F>::ReturnsFuture::value, futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
onError(F&& func); onError(F&& func) &&;
/// Overload of onError that takes exception_wrapper and returns Future<T> /// Overload of onError that takes exception_wrapper and returns Future<T>
/// ///
...@@ -1456,7 +1456,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1456,7 +1456,7 @@ class Future : private futures::detail::FutureBase<T> {
is_invocable<F, exception_wrapper>::value && is_invocable<F, exception_wrapper>::value &&
futures::detail::Extract<F>::ReturnsFuture::value, futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
onError(F&& func); onError(F&& func) &&;
/// Overload of onError that takes exception_wrapper and returns T /// Overload of onError that takes exception_wrapper and returns T
/// ///
...@@ -1474,7 +1474,12 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1474,7 +1474,12 @@ class Future : private futures::detail::FutureBase<T> {
is_invocable<F, exception_wrapper>::value && is_invocable<F, exception_wrapper>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value, !futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
onError(F&& func); onError(F&& func) &&;
template <class F>
auto onError(F&& func) & {
return std::move(*this).onError(std::forward<F>(func));
}
/// func is like std::function<void()> and is executed unconditionally, and /// func is like std::function<void()> and is executed unconditionally, and
/// the value/exception is passed through to the resulting Future. /// the value/exception is passed through to the resulting Future.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment