Boost logo

Boost :

Subject: Re: [boost] Noexcept
From: Emil Dotchevski (emildotchevski_at_[hidden])
Date: 2017-06-20 20:44:53

On Tue, Jun 20, 2017 at 2:16 AM, Andrzej Krzemienski via Boost <
boost_at_[hidden]> wrote:

> > > > > 3. I want validation failers to be handled immediately: one level
> up
> > > the
> > > > > stack. I do not expect or intend to ever propagate them further.
> > > >
> > > > You can catch exceptions one level up if you want to. Right? :)
> > >
> > > I can. And it would work. But it just feels not the right tool for the
> > job.
> > > It would not reflect my intention as clearly as `outcome`.
> >
> > That's because (in your mind, as you stated) you're not using Outcome to
> > handle "real" errors.
> Maybe you are right. Of course "real" and "unreal" are very subjective,

"Subjective", as in sometimes the correct design is not obvious or there
are competing design goals which make it difficult or impossible for the
library to define universal postconditions for a function, as it is often
the case in boost::filesystem. In this case, something like
Outcome/Noexcept helps, by shifting the responsibility to use the correct
postconditions to the user. But this is not typical.

> When writing a low-level asynchronous library
> like AFIO, situations like not being able to open a file or write to it at
> a given moment should not be treated as a "real error", because at this
> level, in this context, there is no corresponding postcondition.

Usually there is. The postcondition for a write function is that the data
has been successfully submitted to the file system, because it is very rare
that the user wouldn't care, in which case he can write a wrapper that
ignores all errors.

> But still,
> a dedicated library for representing variant return values is needed. and
> `variant` is not good enough.

The need is for an error handling library that doesn't use exceptions --
how exactly it works is a matter of design. In my view it is not a good
idea to burden return values with having to transport error objects
because, as the Outcome review showed, that creates a ton of competing
goals and it is very difficult (perhaps impossible) to address all or even
most of them without stripping the outcome<> type from all meaningful
error-handling semantics, effectively turning it into variant<>.

> ```
> outcome<T> append_Y(T t, Y y);
> outcome<T> fun(X x, Y y)
> {
> outcome<T> t = make_X(x);
> return append_Y(t, y); // fails to compile
> return append_Y(TRY(t), y); // ok, and safe
> }
> ```

With exceptions you would do:

T append_Y(T t, Y y);
T fun(X x, Y y)
  return append_Y(make_X(x),y);

The "fails to compile" -- which in the case of Outcome serves the purpose
of making sure that you don't forget to check for errors -- is gone because
the compiler checks for errors for you. Literally, in this case Outcome
protects you form a logic error that is impossible to make if you use

Boost list run by bdawes at, gregod at, cpdaniel at, john at