This design is intentional. *If* you learn off the "rescue semantics" as you put them, then when writing code you swap tedious boilerplate for code which relies on those rescue semantics.
Yes, I think I understand what you are saying. If `o.error()` has a "narrow contract" or IOW, if it has a precondition, many users (but not all) would be forced to manually repeat the same unpacking code:
``` if (o.has_value()) use (error_code_extended{}); else if (o.has_exception()) use error_type((int) monad_errc::exception_present, monad_category()) if ...
```
Correct. The default actions aim to do a useful action on use, thus allowing the programmer to skip manual checks. They can of course still manually check if they wish to override the default action.
If you feel that a woolly and imprecise step too far, then you can use expected<T> instead. It's why Outcome ships with expected<T>. Each of its observers come with strict preconditions governing whether the call is valid or undefined behaviour.
I probably could, but it sounds like `outcome<>` didn't have anything else to offer except the "wooly semantics", and I do not think it is the case.
I would say that is exactly the case.
It is my understanding that `outcome<>` also offers other things:
- being able to store either an error code or exception_ptr
Yes outcome<T> can store all four states: empty, T, EC or E.
- other convenience interface without "contract widening", like BOOST_OUTCOME_TRY
BOOST_OUTCOME_TRY works perfectly with expected
- other performance improvements
There are no performance improvements. These are the actual
implementations of the public "classes" provided by Outcome:
template
If I want to use the above advantages, but I dislike "contract widening" (or "wooly semantics"), you leave me with no option.
You can use expected
What you could do is to offer two observer functions:
``` o.error_wide(); // with wide contract o.error_narrow(); // with wide contract ```
Don't look at the choice of names, you can make them better, but the idea is you have two functions: one for people who prefer clearly stating intentions at the expense of longer code, the other for people that prefer concise notation.
This is what `std::optional` and `boost::optional` are doing, you get both:
``` *o; // with narrow contract o.value(); // with wide contract ```
Or:
``` if (o == true) // for those who like short notation if (o && *o == true) // for those who like no ambiguity ``` My proposed names:
- as_error() // for wide contract - error() // for narrow contract
It would fit much better with the design of Outcome if these were new typedefs of basic_monad. How about these for the narrow contract editions of outcome<T>, result<T> and option<T>: - outcome_u<T> - result_u<T> - option_u<T> Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/