Boost logo

Boost :

Subject: Re: [boost] [outcome] High level summary of review feedback accepted so far
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-29 15:05:19


>> - error_type& .error_raw() - reinterpret_cast<error_type&>
>
> evidently we don't like the _raw suffix.

.error_unsafe(), .unsafe_error(), .unchecked_error() all work for me too.

For me operator*() and operator->() absolutely needs wide contracts. If
people want the performance of narrow, they can manually write out
excpt.value_raw()->var rather than excpt->var, or subclass expected with
a narrow reimplementation of operator*(). It won't kill them.

>> Outcome distinctly categorises failure-due-to-error and
>> failure-due-to-exception. I think that important given its different use
>> case to Expected which is explicitly for low latency and C++ disabled
>> environments.
> Do you mean exceptions disabled?
> How would you have exceptions when the exceptions are disabled?
>>
>> But Expected as the STL type, I think your proposal is safe. Most of
>> your users will throw exceptions for exceptional situations.
>
> I guess that when exceptions are disabled, an implementation will just
> terminate the program, isn't it?.

Not at all. Indeed MSVC can still throw and catch exceptions with
exceptions completely disabled so long as the throw is caught before
leaving the stack frame in which the throw is done.

For all major compilers, you can compile some files with C++ exceptions
enabled, others not. exception_ptr is safe to transport thrown and
caught C++ exceptions through exceptions disabled code. You can thus
"bundle up" usage of the STL into islands kept separate from the rest of
your code, and pass thrown and caught exceptions between islands of
exceptions enabled C++ using Outcome.

> I can not ignore this Outcome review, but I have not see too much people
> saying that the semantic you have done to this functions is the good one.

Strange. I've been surprised at how little criticism there has been of
my design choices. Silence can be interpreted both ways I guess.

> Nevertheless I will add an open point about having narrow and wide
> contract for the error access.
> I will add also another open point to have the possibility to return E{}
> when the contract is wide instead of throwing an exception.
>
> IMHO we need just the narrow contract function. The other can be built
> on top of this by the user or by Outcome.
>
> Remember Expected proposal has already two open_points for
> err error_or(exp, err) and
> bool has_error(exp, err)

I do agree with this philosophy, but if you're going to go narrow, you
need to go narrow on everything including .value(). You need to
consistently choose one or the other. No middle ground.

An advantage of all narrow is you can eliminate bad_expected_access and
simplify the Expected proposal to be merely a thin API convenience layer
wrapping std::variant. A separate std::result, as Peter suggested, can
layer on top of std::expected with all wide observers as would make much
more sense for an object returning uncertainty. But it's up to you.

>>> What your checked_outcome<T>::error will return if the is a
>>> exception_ptr?
>> Ah, finally someone brought this up. Good!
>>
>> It returns an error_code with bad_outcome_category and
>> bad_outcome_errc::exception_present.
>
> Ugh. Why your design is never coherent. Why you don't name your
> functions after what they do?

I would call my design asymmetrical. I can see why some would call it
incoherent.

> What if the exception_ptr contains an arbitrary exception? No way to
> obtain an error_code :(

There is a macro to do that in the presented library. Peter has
discovered it to be over engineered given current compilers, and so
https://github.com/ned14/boost.outcome/issues/50 will replace it.

> I believe your design is too much guided by your AFIO use case. Not all
> the applications use system errors.

As the documentation tries to show, Outcome only makes sense for those
users of expected<T, E> where E being hard coded to an error_code makes
sense for them i.e. where causes of failure are unpredictable and come
entirely from external code like the OS.

Once you are in that territory, you are exactly where AFIO is as a low
level system library, and Outcome suits very well. If you were
application code with many disparate third party libraries with
different error coding, it would also suit well. If you are application
code with a single vision for all error possibilities, expected<T, E> is
a better choice. If you are constexpr programming, expected<T, E> is
literally the only game in town, Outcome can't work in constexpr.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk