
Hello, On 04/22/2013 06:45 PM, Gottlob Frege wrote:
A few thoughts about expected<> :
I think comparison with optional<> is worthwhile. In fact, I think we should consider small changes to optional, if necessary, if it helps them align. Specifically I'm thinking of the cast to bool. Does the below conversions to bool bother anyone?
std::expected<int, Err> exp = ...; std::optional<int> opt = ...;
if (opt) { ... }
if (exp) { ... }
And if that doesn't bother you, change the 'int' to 'bool' above.
I don't care which way it goes (the alternative being a explicit function call, like exp.valid() or is_valid() or...), but I think it makes sense for expected and optional to work the same way, and currently, optional<> is set to work in the above. So if you really dislike if (exp), then you have an uphill battle to change optional, which was just accepted.
As for comparing "exceptions", I'm not sure the exception part of expected should be always considered an exception. Maybe it is just the "false case" type. ie
expected<true_case, false_case> or expected<expect_type, else_type>
or however you want to think of it.
I would only call it an *exception* type if it gets thrown when trying to access the value of a false expected:
You right, we should align on std::optional, at least for the bool cast.
std::expected<int, Exception> exp;
int x = exp.value(); // has no value - does this throw bad_expected_access, or does it throw Exception()?
Actually, expected contains an error and we don't know anything about the type of the error so we cannot throw it. It's what I called expected_base<T, Error> in my previous mails, the get() on expected_base doesn't throw and if expected_base doesn't contain a value, then undefined behavior occurs. Currently, we thought about two refinements of expected_base, the first is expected<T> as described by Alexandrescu in his talk. It contains some nice features related to exception, so in this case, the get() throw the contained exception if it doesn't contain a value. The second is expected_or_error<T> in which the error is a std::error_condition. The behavior of the get() method is not yet well-defined and could eventually throw a bad_expected_access. One of my concerns about it, is the double check: if(e.valid()) // test if e is valid f(e.get()); // re-test And this is why the get() method in expected_base doesn't contain any check. Another concern is about the class name, in my proposal, expected and expected_or_error privately inherits from expected_base. expected should be named "expected_or_exception" to be logic. This is relevant because it means that the design is unclear and we "favor" the Alexandrescu expected instead of having an expected<T, Error>.
I think answering these questions might help answering the comparison questions. ie first know what expected<> really is.
Tony
Should expected be a generic component on the error type such as Expected<T, Error> (and with refinements for exceptions and error_condition), or should it be the Alexandrescu Expected<T> with another class specialized for error code that aren't exception ? I quite digress from your initial questions, but you made realized some important points. Thanks for the comments, Pierre T.