Forgive me chiming in late, but what is the semantic difference between: enum class no_difference { _ } expected<std::path, no_difference, std::error_code, std::exception_ptr> and this: using path_difference = std::variant<std::path, no_difference>; using error = std::variant<std::error_code, std::exception_ptr>; expected<path_difference, error> return_first_diff(...); Doesn't the latter form satisfy all concerns in that: 1. It conforms to a desirable 2-state 'value or error' KISS paradigm. 2. it contains all the information we'll ever need. 3. success code paths are now co-located, as are failure code paths. There is no need for N code-paths to cater for N states. Isn't this more maintainable? On 2 June 2017 at 18:11, Robert Ramey via Boost <boost@lists.boost.org> wrote:
On 6/2/17 8:42 AM, Peter Dimov via Boost wrote:
Robert Ramey wrote:
And wouldn't making these things immutable, eliminate a large part of the
whole controversy?
An immutable result/outcome would have no default constructor (because it's default-constructed only in cases you need to put the value into it later) which would eliminate the motivation for an empty state as something into which to default-construct... but that's only a small part of the whole controversy.
Right - so it would only eliminate a small part of the whole controversy.
Niall's argument for empty state does not rest entirely on default
construction. He argues that it makes Outcome a four-state variant instead of a tri-state one and having the fourth state is useful in certain scenarios when the function that returns it has a legitimate need to report four states.
That is, he wants to be able to express this:
enum class no_difference { _ }
expected<std::path, no_difference, std::error_code, std::exception_ptr> void return_first_difference( std::path const & p1, std::path const & p2 ) { // ... }
(or something along these lines, I may not have gotten the example entirely correct, but that's the spirit of it.)
OK - I guess then that "expected" wouldn't be consistent with my expectations for a function result - which for me is the main (or only) use case. In my world, I would expect
template<class T, class E> struct expected {...};
expected<std::path, no_difference> void return_first_difference( std::path const & p1, std::path const & p2 ) { // ... }
then use it like this
std::path p1 = "asdfasdfsdf"; std::path p2 = "34234324";
const expected<std::path, no_difference> result = return_first_difference(p1,p2);
if(result) // convertable to bool? // convert result to error_code const std::error_code e(result, error_catagory); throw ? std::system_error(e)
const std::path path = result;
I don't see why expected has to have more than two states. One for the legitimate result and one for anything else. The "anything else" doesn't have to be dealt with inside of "expected". Basically the E parameter is an "Escape" clause which is the user's responsibility to define.
There are different legitimate ways to draw the line; you could say three
states are it, for more use expected<>, or you could say, four states cover the majority of the legitimate cases, so let's have that.
Hmmm - maybe states and parameters are getting confused. An "Escape" parameter can contain an arbitrary number of states in one parameter.
Robert Ramey
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman /listinfo.cgi/boost