Le 13/06/2017 à 01:01, Niall Douglas via Boost a écrit :
Still, I fail to see how Noexcept differs from Outcome in this aspect.
Semantically the only difference is that Noexcept doesn't force users to
use a special template in return types, but that's a good thing. If it's
preferable, they can still use a special template, and if they do, it's
trivial to design because it doesn't have to transport errors -- Noexcept
takes care of that for you.
You *want* APIs to clearly indicate their failure contract.
Relying on TLS trickery hides control flow paths. And if people fail to
write the check, errors get lost or pop out in the wrong locations.
Forcing a wrapper type to be used also allows [[nodiscard]] to be
leveraged, and in the future static analysis to be applied. Neither
works with your scheme, which is why I rejected it very early on.
Finally, Rust and Swift have adopted a Result model. It is
generally viewed as a good design choice for its problem domain. Varying
significantly from what the other system languages are doing needs to
have very strong rationale.
AFAIK [1], the proposed library and Swift error handling mechanism are
very close. Swift has alternatively also used Result as we could
have expected.
The main difference I see is that one is library based and the other
language based.
In Swift you signal that a function can throw adding throws() to the
signature. Swift has builtin optionals and adding throw is almost like
declaring it to return T? (optional<T>.
You cannot call this function without using try, try! or try?
IIUC, with Noexcept, you cannot require this as it is a library. However
when the user uses try_ it is able to control whether the call succeeds
or fails.
In order to force it, the closer is to use a return type that tell you
that there could be errors, as return_<T>.
I will say that if Noexcept required this return_<T> type, it will be
like outcome<T>, except that the error is transported using TLS instead
of using the stack (please let me know if I'm wrong)
However if Noexcept doesn't require a return_<T> then it is much
difficult to force the use of the try functions. But it works yet.
I see advantages in this approach and I don't know which one is more
efficient in the success and failure cases. Some measures will be more
than welcome.
I'll rename Noexcept to ErrorTLS
In summary,
do we want an error handling mechanism in C++ based on Swift error
handling ;-) ? Do we want a library that emulates it as Boost.Noexcept
in Boost?
do we want a monadic error handling in C++ as Result in Boost?
do we want both in Boost?
I believe both merit to be tried.
Vicente
P.S. I've not read the full documentation yet, but this seams promising.
[1] https://www.cocoawithlove.com/blog/2016/08/21/result-types-part-one.html