Le 25/05/2017 à 16:14, Niall Douglas via Boost a écrit :
In fact, I am increasingly thinking that a consensus position could be this type factory template:
// What to default construct to enum class default_to { none, T, EC, E };
none => 1
// How much empty state to implement enum class emptiness { never, // imposes restrictions on T, EC, E formal, // formal empty state tolerant // empty state iff EC and E don't have nothrow move construction };
never => 1
// How narrow or wide the observers will be enum class observers { narrow, // accessing not the current state = reinterpret_cast wide, // default actions already described earlier this review single_shot // you can observe state precisely once only };
narrow and wide => 1
// Replacement for basic_monad template< class T, // what .value() returns, or void class EC, // what .error() returns, or void class E, // what .exception() returns, or void default_to default_to_config, emptiness empty_config, observers observers_config
class outcome_impl; // Outcome as apparently desired by reviewers template<class T> using outcome = outcome_impl< T, error_code_extended, std::exception_ptr, default_to::none, // default constructed instance = reinterpret_cast uninitialised memory emptiness::never, // Never possible to be empty, not ever observers::narrow // reinterpret_cast all observers ; // Result as apparently desired by reviewers template<class T> using result = outcome_impl< T, error_code_extended, void, // there is still a .exception(), but it returns void and is not usable default_to::none, // default constructed instance = reinterpret_cast uninitialised memory emptiness::never, // Never possible to be empty, not ever observers::narrow // reinterpret_cast all observers ; See what you think of the proposed API above. We supply a precanned outcome<T> and result<T> template alias, but end users can template alias any configuration they like.
I am geting some contradictory information here. Is the fact that outcome<T> is built of policies part of the API which you commit to support in subsequent releases? It was my impression that you never wanted this to be exposed to the users. Now, when you use name "API" it looks like you do want to expose the policies? Outcome was always supposed to be a *family* of Either monad varieties which had well defined interoperation semantics with one another. So the original idea was that there was a clean progression from option<T> right through to future<T> with a single common implementation, with a common DO/TRY/AWAIT mechanism, a common monadic BIND and MAP mechanism and so on. I believe that some of us want these mechanism to be provided independently of the concrete classes. No a single class that wraps some data and provides all these mechanism.
However I am personally uncomfortable supporting code I don't use in my own software, so after AFIO v1 was rejected, my personal need for such a wide family of Either monads, and the monadic operations, went away, including the promise/future specialisation. You thus got the Outcome presented for review here today which had been reduced to just outcome, result and option.
During this review there are clear disagreements about what form and semantics a C++ Either monad should take. People aren't even sold on the Expected proposal. I don't get that criticism, I think the Expected proposal just fine, but there you go. But we can also other Monads that don't fall on the PossiblyValued category. E.g. we can see array, tuple, vector as monadic types. And a lot more that I don't know yet.
Outcome's CRTP policy based implementation is very flexible. All the code to implement all the varieties of Either monad which someone has asked for at least once in this review is already in Outcome. It would be a bit of work, but not too awful, to replace the preprocessor stamping out of hard coded prefabricated specialisations for outcome, result, option and expected with a template based compile time assembly of parts to provide all the varieties mentioned above. I count:
4 x 3 x 3 x 3 combinations = 108 Either monad varieties I don't agree with the template parameters you are suggesting and I believe that there are no so much concrete cases. We shouldn't provide any combination some one could be ionterested in just in order to satisfy this guy. We should start with the concrete ones people really need.
BTW, I see only 4 x 3 x 3
You can't possibly hope to test all these in a test suite. It's another reason why I didn't propose this design originally. But if it's what people want, and it's not stupidly dangerous which this is not, I can give the people what they want.
:)
(BTW, originally Outcome *did* use a template based compile time assembly of parts. I replaced it with a hard coded preprocessor generated edition for lower compile time cost. But the old mechanism can be restored, and that would eliminate most of the preprocessor template based code generation which some have complained about. I personally suspect the template based system will be not particularly easier for casual reading)
So do I want to expose the policies? Not really. But I can see no consensus opinion on the shape and form for Expected, let alone for Outcome, will emerge. So I propose Outcome provides all one hundred and eight varieties of Either monad, and let Boost keep its reputation for overwhelming complexity.
No please.
We'll see which forms end up being used most by end users, and that would be great information for Vicente and WG21 to have to hand during standardisation. It is simpler than that. Just propose the concrete classes that have a sense.
We could discuss here on which emptiness, default value, contract do we
want for these classes.
IHMO we should base always our interface and decision on the experience
of the standard library (I'm not saying we should copy/past the design
that we did wrong).
We have std::varaint that doesn't provide the never-empty warranties.
This IMO was a mistake. We spent a lot of time with the specification of
this library. C++17 was too close to reopen the debate. I will hope we
will restart it for C++20 with the papers from Anthony W., Peter D. and
David S. I would prefer to have a variant that doesn't provides some
operations when the types don't satisfy some properties but that respect
the never-empty warranties. We need correction before optimization.
For the default value, each option is not better than the others and
seems arbitrary. In this case I would say that either we don't provide
it or it is provided uninitialized. Why variant