Boost logo

Boost :

Subject: Re: [boost] [outcome] Ternary logic -- need an example
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-18 22:49:03


> 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.

Ah but remember that outcome<T> and result<T> both guarantee that E will
be a type meeting the std::error_code contract.

Therefore calling o.error() on a valued outcome returning a default
constructed (null) error code is exactly correct: we return there is no
error. No undefined behaviour needed, and you can write your code using
Outcome with the hard assumption that o.error() will always return an
accurate view of the current state. No need to check .has_error(), or
anything like it.

> 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.

No static analyser that I am aware of can diagnose when someone is
causing UB in std::optional<T>. Writing one which didn't spew false
positives would be hard, even if the entire program were visible. After
all, maybe the user is _intentionally_ doing the reinterpret_cast by
effectively treating the common state as a union?

Remember, expected<std::error_code, std::error_code> is legal, though
Outcome's Expected doesn't allow it.

> 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()`?

I don't want to talk about this much as it's outside the scope of the
current review, but in functional programming using Outcome the tribool
can help make the logic much clearer. A common pattern I've used
personally is for true and false to select which branch of lambdas to
call next, and empty means to terminate processing immediately with no
further functions called.

I should emphasise that those extensions are disabled in the presented
library, and are out of scope for this review.

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