2017-05-15 23:42 GMT+02:00 Niall Douglas via Boost
It doesn't have much to do with tribool. outcome<T> and result<T> deliberately take a three state based design with an explicit choice of ternary instead of binary state. The original motivation was actually for the basic_monad based, since removed, non-allocating future-promise implementation where we needed a third state to indicate "pending", but it turned out to be very useful in itself for simplifying usage, eliminating writing boilerplate, and acting as an out-of-band signalling mechanism.
Ok, so by "ternary" you mean "eihter value, or error, or just nothing".
It's more than that. Originally before I wrote any code, I drew up the design on a whiteboard with the exact semantics for all possible permutations of all possible operations based on the three state logic. It was there that I decided that the valued state corresponds to ternary value TRUE, the errored state corresponds to FALSE, and the empty state to OTHER.
Now that choice is quite controversial. Here on boost-dev we bikeshedded that choice for some weeks if I remember correctly. Many felt that empty should be FALSE, and errored should be OTHER. But I'm sticking to my guns on that, I still think my assignment is the right choice.
The OTHER state gets treated as truly other, and it's why it gets the strongest abort semantics of any of the states. It is considered to be the most abnormal of the three possible states by the default actions by observer functions.
The above explanation, treated in isolation, makes sense to me: empty is the most abnormal state. But in the other thread, you say: But the point being made (badly) in the example above was that you can
use the empty state to indicate lack of find, and any errored state for errors during find etc. So, let me rewrite the above now it's morning and I am not babbling incoherently:
outcome<Foo> found(empty); for(auto &i : container) { auto v = something(i); // returns a result<Foo> if(!v.empty()) // if not empty { found = std::move(v); // auto upconverts preserving error or Foo break; } } if(found.has_error()) { die(found.error()); } if(found) { Do something with found.value() ... }
This seams to be implying something opposite: that empty can can be treated as less abnormal than error. It is my impression that the system of types in Boost.Outcome confuses two meanings of "empty" option<T> -- either T or "empty" -- in this case "empty" looks like "just another state of T", as in boost::optional result<T> -- either T or an error or "empty" -- in this case it means "abnormally empty" Am I right? If so, maybe you need two separate states "simply no T" and "abnormal situation"? Regards, &rzej;