Le 24/05/2017 à 15:15, Andrzej Krzemienski via Boost a écrit :
Niall, What do you think about the following alternate interface of outcome types?
1. Remove option<T> altogether.
2. result<T> (and outcome<T>) does not have a separate empty state. Yes please.
3. A default-constructed result<T> is initialized as if `result<T>{error_code_extended{}}`. It is curious, the original expected<E,T> default initialized to E{} :) as I copied from optional. We moved to expected<T,E> and a default construction as if T{} for two reason, to behave like T and to avoid this default construction of exception_ptr.
4. Function r.empty() is implemented as `r.has_error() && !error()`.
So you are requesting that error is explicitly convertible to bool. This could work for outcome and result as the errors provide it but not for expected<T,E>. I don't believe the library should make use of this bool conversion. Even the opposite. I will add a pre-condition that the Error value if convertible to bool is equal to false (this can be also cheched at run-time).
5. Framework requires that type E in `expected<T, E>` is default-constructible, and its default-constructed value represents no error condition (already the case for exception_ptr, error_code).
This is something that the library cannot check without adding more constraints. The interpretation that the user does of each one of the values of E is up to him. If the Error parameter is not an error but a status, maybe the user should consider the status_value<S, T> proposal, which is isomorphic to pair<S, optional <T>>. In this proposal, some of the status values mean succeed and others mean failure. The second is not empty if the status mean success. The default construction of exception_ptr is IMHO an accident. If the user uses values of Error that doesn't mean an error, you have a tri-state. IMO, the use error_code{} or exception_ptr{} with outcome or expected is an ERROR. At the end I'm not sure result<T> or expected<T> should have a default constructor. Note that we want variables initialized at the declaration and the default construction of these types is always artificial.
The rationale behind this is my assumption that `option<T>` is not as useful as the other types. (Or can you give an example to the contrary?) That there was no initial business need for an empty state, and the examples that illustrate its usefulness are just exploring how we can make use of it now that it is there. (Or am I wrong here?)
I noticed a number of people report negative feedback about this empty state. Getting rid of it would take result<T> closer to "either T or reason for failure".
What do you think?
I agree with the non-empty, but disagree with the possibility of Error to mean a Status. This make the user code more complex. Concerning the default construction, I'm inclined to think that in this cases the best is to don't initialize as a T or as E. Note that this doesn't mean to add an additional state. The result of default construction is just a partial initialized state that needs either to be assigned or destructed, as if we had do a move. Trying to use has_value on this state will be UB. The advantage is that IMO, is that we don't spend more time than we need. Not all types should have a well formed object as default value (See e.g. chrono::duration, Date). Best, Vicente