boostorg / leaf

Lightweight Error Augmentation Framework
Boost Software License 1.0
302 stars 48 forks source link

Question: How to correctly rethrow/propagate? #43

Closed tchatow closed 2 years ago

tchatow commented 2 years ago

I have a situation that looks something like this, which I am attempting to translate into LEAF:

try {
  MaybeThrowingOperation();
} catch (const my_error_type&) {
  if (/* conditional */) {
    throw;
  }
}

The conditional is not part of the exception type, but comes from the surrounding block, so it seems I can't use a matcher. I also considered simply returning leaf::new_error(e), but if some on_error data was attached, this would be discarded. I found leaf::current_error() which seems to do the trick. Is using that correct or is there a better way to "rethrow"?

boost::leaf::try_handle_some(
  [&] -> boost::leaf::result<void> {
    // Some operation that returns either a valid result<void>{} or a result with an error_id.
  },
  [&](const my_error_type&) -> boost::leaf::result<void> {
    if (/* conditional */) {
      return boost::leaf::current_error();
    } else {
      return {};
    }
  });
zajo commented 2 years ago

Thanks for this, the tutorial is missing this important information, I'll add it tomorrow.

You do it like so:

boost::leaf::try_handle_some(
  [&] -> boost::leaf::result<void> {
    // Some operation that returns either a valid result<void>{} or a result with an error_id.
  },
  [&](leaf::error_info const & e, const my_error_type&) -> boost::leaf::result<void> {
    if (/* conditional */) {
      return e.error();
    } else {
      return {};
    }
  });

Any error handler can take leaf::error_info const &, it is always available.

As you've discovered, leaf::current_error does the trick also, but it may not be correct if you have multiple errors "in flight".

zajo commented 2 years ago

I updated the error handling section in the documentation.

tchatow commented 2 years ago

Thanks, this works perfectly.