Le 22/05/2017 à 00:12, Niall Douglas via Boost a écrit :
Outcome doesn't do SFINAE on its main constructors. It relies on simple overloading which is much lower compile time cost. Maybe it has lower compile time, but it is not correct, isn't it? Would you suggest that std::expect shouldn't do SFINAE? Outcome's Expected provides both a subset and a superset of your Expected proposal.
I have promised to track closely your proposal paper, but I have no interest in providing a perfect match to your proposal. Outcome lets you seamlessly mix expected
with Outcomes and with *any arbitrary third party error handling system* thanks to the policy based core implementation. It therefore cannot exactly implement your proposal, it needs to differ because it *is* different. My claim is that any code written to use LEWG Expected will work exactly the same with Outcome's Expected. If it does not, I will repair Outcome's Expected until code using it works identically. I think this a very reasonable position to take, especially as you are still changing the proposed Expected. You are right it is moving and not yet accepted. One of the major interest I have in this review is to try to see what can be improved on the proposed std expected.
At the risk of slightly losing my temper, I need to say something I'll probably regret later when people throw axes at me. But it's been building for a few days now, and I need to vent. I understand you. Both you and Vinnie have called Outcome "over engineered". I respectfully suggest neither of you understands the purpose of Outcome the **framework** which is to provide a very low overhead universal error handling framework. That's why there is the exact same CRTP policy based basic_monad class being typedefed into the aliases expected
, outcome<T>, result<T>, option<T>. They are all the same class and object, just with policy-determined "personality" that lets them provide differing semantics to each user, yet they all still operate seamlessly together and can be fed into one another e.g. via the TRY operation, and with very low, usually minimum, runtime overhead and low compile time overhead. Okay. Has this clearly stated and showed throw examples in the documentation? Sorry, I have not read all the documentation yet. IIUC, what you want is to have outcomes that copy/move well each one on each other. Is this the major drawback you find to the use of std::expected and std::optional? If you are only in the market for just an expected implementation and nothing else, then yes Outcome looks over engineered. But my claim is that in any real world code base of any size, people end up having to add layers on top of expected etc to aid interop between parts of a large code base. I recognize there is a problem when we need to forwarding errors that are transformed. This is my TODO plan for the standard proposals. Maybe my approach would be what you consider is the way we shouldn't follow. We will see. They will have varying degrees of success, as people on Reddit have told me regarding their local expected implementations. A lot of people end up with macros containing switch or try catch statements to map between differing error handling systems. And that is bad design. This transformation can be hidden by higher level abstractions, but IMO they should be invoked explicitly. I will claim that if you *are* building such an interop framework, you will find that Outcome is the bare minimum implementation possible. Maybe or maybe not. If outcome uses more storage than expected or optional it is not the base minimum. It is, if anything, *under* engineered compared to the many other "universal error handling frameworks for C++" out there which tend to throw memory allocation and smart pointers and type erasure at the problem. Niall sorry, I don't like the worlds "universal" and similar qualifications as "ultra-lightweight error handling" and "minimum overhead universal outcome transport mechanism for C++" To what other "universal error handling are you referring? Ho wis your design universal? Outcome doesn't do any of that, it never allocates memory, has highly predictable latency, I hope so :) runs perfectly with C++ exceptions disabled, This is an interesting point. I will add it to the goal of your library. What is the behavior on the absence of exception on the functions that throw exceptions? Are these functions disabled? Does the fucntion terminate? Calls a handler? is an excellent neighbour to all other C++ libraries as for example? AND build systems, I'm less concerned by the build systems, but could you elaborate? and avoids where possible imposing any constraints on the user supplied types fed to it. It also lets you use as much or as little of itself as you choose. It is not imposing the use of boost::outcome? Does it interact well with std::expected and std::optional and boost::optional? I see that you responded in another mail No. So okay, it's over engineered if you think you want just an expected . But as soon as you roll expected out into your code, you are going to find it won't be enough. Thus the rest of Outcome comes into play, and even then there are small gaps in what Outcome provides which any real world application will still need to fill. That's deliberate *under* engineering, I couldn't decide on what was best for everyone, so I give the end user the choice by providing many customisation points and macro hooks.
I must recognize I'm reluctant to the basic_monad abstraction, and of course if the library is accepted should change of name. I'll need to take a deeper look, but I don't know if we are reviewing basic_monad it or if it is there by accident?
I'll respond to your other comments in a separate reply. I just needed to unload the above,
I understand.
and I appreciate that the docs do not sufficiently get into the universal error handling framework part of Outcome. That is due to repeated Reddit feedback telling me that earlier editions of the docs didn't make sense, and I needed to go much slower and hold the hand, so you got the current tutorial which as you've already observed, is too long as it is. It would become even longer if you started dissecting universal error handling strategies. If the main goal is the universal error handling strategies, then the documentation must describe what this is? (And my thanks to Andrzej for the motivating example on the landing page of the docs, he did a great job capturing the universal error handling framework aspect of Outcome. I would love to know if reviewers can make sense of it, or did it just confuse the hell out of everybody)
Could you tell us which example? Best, Vicente