But you might be onto something. Some other combination with value_or() might well produce a reference to a deleted temporary. That would explain the choice of value returning semantics for value_or().
Having value_or at all is wrong. expected shouldn't have it. It encourages people to drop the error code on the floor.
I really don't think it does. I've certainly never felt encouraged to do that. I use .value_or() mostly in constexpr or functional use cases. I don't think I've ever used it outside those. But then I don't believe in artificially constraining users unless it's really bad for their health. I give them what they (think they) want.
expected does give you the reason. This reason should be acknowledged, not ignored or silently dropped.
Back at the beginning when designing Outcome, one of my design ideas was a variety which called std::terminate on destruction if an error had never been retrieved. So, the idea behind this family of Outcomes was that they were "single shot", .error() and .value() could be called exactly once after which the outcome became empty. On destruction, if an error had never been retrieved, it was fatal exit time. I never found a use for that particular variety in my own code, but I find the semantics very attractive. They impose rigour. I just wish I could make the statically obvious failure to collect state a compile time instead of runtime error. I could be very easily persuaded to go ahead and add that variety (recommended naming is welcomed!).
This is but one example in which "consistency" (in this case between optional and expected) makes an interface worse. These two are different things, they shouldn't be consistent. op->? Really?
This is also why I don't care much for Niall's decision to include option<T> in his library, with the consequent bubbling up of option's properties (such as the ability to have an empty state) upwards into result/outcome.
You are wrong that the option<T> => anything emptiness preservation was a motivation of mine. I was far more motivated by the power of the state of "empty" to simplify end user code. For example, the example above or the for loop examples I've mentioned before. If one were to implement the rigorous outcomes described above, you'd have implicit conversion from any less rigorous outcome to any more rigorous outcome, but require explicit conversion in the opposite direction.
Sure, now that one has the empty state, one can make it do something useful, such as make error() throw when empty, so that its utility becomes a self-fulfilling prophecy. But it shouldn't be there. result/outcome would be cleaner and more elegant without option and the empty state (and result<T> could be brought as close as possible to expected
, an equivalence everyone expects.)
Would you still say the above after considering my idea for a family of "rigorous" outcomes? Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/