Boost logo

Boost :

Subject: Re: [boost] [outcome] Ternary logic -- need an example
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-05-18 20:43:45


2017-05-18 17:06 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:

> > This seams to be implying something opposite: that empty can can be
> treated
> > as less abnormal than error.
>
> You're forgetting locality. Locally to the find loop, the valued or
> errored state returned by something() is the normal situation and you
> don't care which it returns. Locally to the find loop, failing to find
> what we are looking for is the abnormal situation.
>
> The programmer looking at the find loop won't be thinking in terms of
> errors or success of something(), but rather that the flow of execution
> in the find loop is correct or incorrect.
>
> I really should emphasise that this stuff, when used in practice, is
> nothing like as complicated as this thread of discussion is making it
> seem. Any programmer, even an undergrad, will look at that find loop and
> know exactly what it means and how it works intuitively.
>

Ok, I misunderstood your example (maybe because I am not an undergrad :),
sorry. Indeed, it treate an empty state as the most abnormal.

>
> > It is my impression that the system of types in Boost.Outcome confuses
> two
> > meanings of "empty"
> >
> > option<T> -- either T or "empty" -- in this case "empty" looks like "just
> > another state of T", as in boost::optional
> > result<T> -- either T or an error or "empty" -- in this case it means
> > "abnormally empty"
> >
> > Am I right? If so, maybe you need two separate states "simply no T" and
> > "abnormal situation"?
>

Now, my above observation is invalid.

>
> Empty is *defaulted* to the most abnormal state by Outcome's default
> semantics. So if you call .error() on a valued Outcome, you get back a
> default constructed error type, no exception thrown. Same goes for
> .exception().
>
> But if you call .error() or .exception() on an empty Outcome, you
> *always* get an exception thrown. Therefore, if you write your Outcome
> using code without state checks before observation i.e. you call
> .error() without checking .has_error() beforehand, you get a stronger,
> more abortive default action than if the Outcome were errored, valued or
> excepted.
>
> You the programmer may wish to avoid the default actions, in which case
> you check state before access. You can then manually specify any other
> action you prefer.
>
> The "more abnormal" solely refers to my design choice of default
> semantics only for the empty state. Reviewers may think those choices
> misguided or plain wrong, and might suggest better default semantics.
> For example, some might feel that any time one tries to observe state
> where the state is different, you should always throw an exception.
>
> That would be a very conservative design choice and I'd disagree with
> it. But I would understand the rationale. I would also add that it is
> trivial to wrap an Outcome with replacement observer functions which
> change the default actions, or to customise the policy class to have
> different defaults.
>

My personal preference on this is that if you call `o.error()` before you
have confirmed you actually have an error, you are doing something wrong. I
would classify such situation as undefined behavior. But your choice fits
into the scope of undefined behaviour: if program can do anything, it might
as well return a default-constructed error_code.

On the other hand, you do loose something when you chose something else
than undefined behavior: the potential for such user bugs to be detected by
static analyzers.

But still, my initial concern remains somewhat un-addressed. I understand
that .empty() is treated as the most ubnormal state. I accept your choice
of throwing an exception upon a call to .exception(), I understand why
someone might want to type:

```
if (o.has_value()) {}
else if (o.has_error()) {}
else if (o.has exception()) {}
else {}
```

But I do not understand why in my program I would want to write:

```
if (o == tribool::unknown) {}
```

How is that better ina any way from `o.is_empty()`?

Regards,
&rzej;


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