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.
I would agree. But well, we were outvoted. And that probably means
rejection of this library, as the presented library does not implement
what the majority want (yet).
I would say that I expect absolutely nobody to actually type
checked_optional_result<T> each and every time. What they'll do is:
namespace mylib
{
template<class T> using result = checked_optional_result<T>;
...
}
Indeed AFIO already typedefs Outcome's result into its namespace to
prevent me typing outcome::result all the time, which is annoying.
Also remember that checked_optional_result<T> will itself be typedefed to:
template<class T> using checked_optional_result = outcome_impl
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.
It's only unchecked on access, so if you store the return type from the API into a checked variety (remember we allow implicit conversion from unchecked to checked, but not the other way round), then the caller gets to choose whether access is checked or not.
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.
Yes, but surely the programmer can see that function() returns a result<T>, not a checked_result<T>. So if they want the throw on error: result<T> function() noexcept; U function2() /*yesexcept*/ { auto r = checked_result<T>(function()).value(); // want throw on error // ... } A free function called "checked()" might be nice to convert some unchecked input outcome into its equivalent checked variety. But that's just sugar.
Since this idiomatic use is one definitive aspect of the error handling philosophy that result/outcome represent, going to unchecked would be detrimental.
I agree. But we were outvoted.
If value/error must be unchecked, then provide checked overloads, instead of a different type. Better yet, keep value/error checked, provide unchecked overloads.
The reason I chose different types is because we can have the unchecked varieties call __builtin_unreachable() so static analysers trap stupid usage of the unchecked objects. Now, that doesn't rule out additional member functions. A decision needs to be made on whether to use type converting free functions like "U &&checked(T &&)" or whether to go with duplication of checked member functions instead. So, should the type system represent the checked vs unchecked semantics, or should it not? I don't know yet. I am still thinking about that design choice. It's why I hadn't mentioned it. But I am on to the problem.
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.
I hate with a passion that choice of giving operator*() unchecked semantics. Why should it be operator*()? Why not .value_raw(), or .value_unsafe()? The latter two would be far superior, not least that if you really want narrow semantics and less safety, the programmer has type more in exchange. But as you say, democracy. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/