On 26/05/2017 07:41, Gavin Lambert via Boost wrote:
On 26/05/2017 17:33, Vicente J. Botet Escriba wrote:
std::experimentall:expected
::error, doesn't throws. I don't see a use case where we want to retrieve an error without checking before. Maybe you have a case. Perhaps unit tests, where you're expecting an error but the code unexpectedly succeeds.
Very true. I have a next gen unit testing infrastructure built around Outcomes where UB on any of the observers would be a no-go. You can see the idea of it at https://github.com/ned14/boost.afio/blob/master/test/tests/file_handle_creat... and note how self describing the tables of success and failure are.
At least in terms of storage, the current implementation of empty state is presumably free (it should be no more expensive to internally store a variant
than a variant ). And it's currently required to exist due to exception guarantees (and possible noexcept(false) move constructors).
As mentioned in another discussion thread, the empty state is also used
internally as a micro-optimisation. So it would likely remain internally
whatever the decision taken here, as a tool for making the CPU expend
identical CPU cycles on both positive and negative branches on state.
Again, if people don't like that behaviour of outcome/result to be
equally costly on T or E branches chosen, expected
I don't think that T should be restricted to noexcept(true)-movable types only, as this prevents using it with C++03 non-POD types (that have a copy constructor but lack a move constructor), which are still likely to be widespread in codebases (although perhaps less common as return values).
I couldn't agree more about type T. But Expected does not demand nothrow move construction from type T, only type E. And usually most of the time the end user will control the source code for any type E used. It's a fair restriction in exchange for never empty.
Another consideration is that regardless of default construction or not is that you need to decide what an expected
will contain if someone moves-from it (directly). Is it now formal-empty or does it now contain a moved-from-T or moved-from-E? Or does it contain a moved-from-variant (if that's different)?
We never change the state unless the user asks explicitly for that. So
if they move from an expected
The return type of value() plays a role here as well. If it returns by value, then you can probably pick whatever you like. If it returns by reference, then the caller can now move-from the internal T and ensure it will be in the has-a-moved-from-T state, not the empty state. (Which may or may not be desirable, but implies that moved-from is not the same as empty, which might surprise users of smart pointers.)
(Returning by reference also disallows possible future storage optimisations from nested variant merging, as mentioned in another thread.)
Reference returning .value() I've found in real world usage to be surprisingly useful. Back when I began using Outcome, I used to write code something like: ``` result<Foo> something() { Foo ret; ... build ret ... return make_valued_result<Foo>(std::move(ret)); } ``` And that's probably what first time users are going to write. But after I built up some experience, now I tend to write this instead: ``` result<Foo> something() { result<Foo> ret(Foo()); Foo &foo = ret.value(); ... build foo ... return ret; } ``` I can tell people are going to ask me: why the second form instead of the first form? That's surprisingly hard to answer in a meaningful way. I guess the former form you are writing code to generate a Foo, and then wrapping that Foo up into result<Foo> for the purposes of indicating success. The second form you are being more specific, you are not generating a Foo, you are generating a result<Foo>. Somehow the code feels right with the second form. It's somehow more idiomatic. I appreciate that's very vague. But my point is, the reference returning .value() makes a lot of sense. You will end up using these objects to build returned values a **lot** in the code you write. In case anyone wishes to study real world code using Outcomes, https://github.com/ned14/boost.afio/blob/master/include/boost/afio/v2.0/deta... is a use case. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/