A correspondent writes to me that he’s switched from throw/catch
exceptions to C++23’s std::expected
in all new code. That is, where a traditional C++ program would have:
int f_or_throw();
int g_or_throw() {
f_or_throw();
// arguably OK, discards f's result
// but propagates any exceptional error
return 1;
}
his programs always have:
using Eint = std::expected<int, std::error_code>;
[[nodiscard]] Eint f_or_error() noexcept;
Eint g_or_error() {
return f_or_error().transform([](int) {
return 1;
});
}
In the former case, we “discard” the result of f_or_throw()
by simply discarding
the value of the whole call-expression. That’s safe, because errors are always
signaled by exceptions, which will be propagated up the stack regardless of what
we do with the (non-exceptional, non-error) return value. This ensures that the
error is never swallowed except on purpose.