Skip to content

Commit

Permalink
Add onError interface to Expected type (#1104)
Browse files Browse the repository at this point in the history
Summary:
So that we can do some thing in the middle or chaining, for example log the error.

While using `Expected`, we found that It's nice to have the chaining operations, but one downside is  there is no place to log each possible error here and there.

So I added this `onError` interface, expecting usage like:

  Expected<D, Error> maybeD = someFunc()
      .then([](A a){return B(a);})
      .onError([](Error e) { LOG_DEBUG("error happened while executing function A->B");})
      .then([](B b){return C(b);})
      .then([](C c){return D(c);});

Pull Request resolved: #1104

Reviewed By: dmm-fb

Differential Revision: D15120090

Pulled By: yfeldblum

fbshipit-source-id: 07bc30c96ede25ef415ff921592f1d8676489b17
  • Loading branch information
Ning Xu authored and facebook-github-bot committed Jul 20, 2024
1 parent 118f7ff commit 7b493b4
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions folly/Expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,19 @@ struct ExpectedHelper {
return makeUnexpected(static_cast<decltype(ex)&&>(ex).error());
}

template <
class This,
class OnError,
class Err =
decltype(std::declval<OnError>()(std::declval<This>().error()))
FOLLY_REQUIRES_TRAILING(std::is_void<Err>::value)>
static This onError_(This&& ex, OnError&& onError) {
if (UNLIKELY(ex.which_ == expected_detail::Which::eError)) {
static_cast<OnError&&>(onError)(static_cast<This&&>(ex).error());
}
return ex;
}

FOLLY_POP_WARNING
};
} // namespace expected_detail_ExpectedHelper
Expand Down Expand Up @@ -1354,6 +1367,37 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
}

/**
* onError
*/
template <class OnError>
auto onError(OnError&& onError) const& {
if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess<void>>();
}

return expected_detail::ExpectedHelper::onError_(
*this, static_cast<OnError&&>(onError));
}

template <class OnError>
auto onError(OnError&& onError) & {
if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess<void>>();
}
return expected_detail::ExpectedHelper::onError_(
*this, static_cast<OnError&&>(onError));
}

template <class OnError>
auto onError(OnError&& onError) && {
if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess<void>>();
}
return expected_detail::ExpectedHelper::onError_(
std::move(*this), static_cast<OnError&&>(onError));
}

// Quasi-private, exposed only for implementing efficient short-circuiting
// coroutines on top of `Expected`. Do NOT use this instead of
// `optional<Expected<>>`, for these reasons:
Expand Down

0 comments on commit 7b493b4

Please sign in to comment.