Niall Douglas wrote:
- outcome<T> and result<T> will have their empty state removed, and all observers gain narrow contracts.
I disagree with the narrow contract change. Wide was correct.
I agree. But we were outvoted,
Were we? :-)
and I've retained the current wide result<T> and outcome<T>, just renamed to checked_result<T> and checked_outcome<T>.
This isn't enough to compensate. One, checked_result is so much longer to type that this is obviously an encouragement to use unchecked by default, a questionable guideline. Two, since result/outcome are used on API boundaries, one can't just declare "we'll use checked_result" because the API you're calling isn't yours and therefore the choice of the return type isn't yours either. If it returns the unchecked result, that's what you'll receive. And it will return the unchecked result. This breaks the idiomatic use of result<T> function() noexcept; U function2() /*yesexcept*/ { auto r = function().value(); // want throw on error // ... } where you're transitioning from a noexcept lower layer that signals errors with error_code, to a higher layer that signals errors with system_error. Since this idiomatic use is one definitive aspect of the error handling philosophy that result/outcome represent, going to unchecked would be detrimental. If value/error must be unchecked, then provide checked overloads, instead of a different type. Better yet, keep value/error checked, provide unchecked overloads. This is another instance where I now see the wisdom in providing a "richer" (another man's cluttered) interface that is, in my opinion, inelegant and unnecessary; in this case operator*. Give people who want unchecked what they want, have plausible argument for calling it op* instead of value ("consistency with optional"). A bit daft if you ask me but what can one do, we were outvoted, after all, and democracy is where it's at.