Boost logo

Boost :

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

2017-05-20 20:01 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:

> > I am not trying to propose any new logic here. I am trying to assign some
> > mental model to what `outcome<T>` currently does. Consider: some funciton
> > `f` is supposed to compute an `int`. But the computation may fail, in
> this
> > case I want the function to return the reason why it failed. Also, it is
> > possible that I will get some "internal error". For this reason funcio
> `f`
> > returns `result<T>`:
> >
> > ```
> > result<T> r = f();
> > ```
> > Now, `r` can represent the following states:
> >
> > ```
> > if (r.has_value()) // value successfully computed
> > {}
> No, the correct interpretation here is that the result returned has a
> value, not that the value was successfully computed.
> > else if (r.empty()) // internal error
> > {}
> > else if (r.error()) // reason why f failed
> > {}
> > else if (r.has_error() && !r.error()) // what is that???
> > {}
> Similarly to the value returned case, Outcome does not involve itself
> into whether a T value returned is valid or not in exactly the same way
> as it does not involve itself into whether a E value returned is valid
> or not.

If you are saying "I just give you a tool for storing either T or
error_code or std::exception_ptr or nothing, and I do not care how you use
it", I can accept that. But the semantics of `o.error()` seem to contradict
that a bit: as though you were in fact trying to workaround for potential
mis-usages of your library.

Given what you already said about semantics of function `error()`, I
consider the documentation of this function insufficient:

(BTW, note that there is something wrong with the links. If I click on it,
I do not get any more details for `error()` but instead get "Detailed
Description" of boost::outcome::v1_xxx::policy::monad_policy_base)

Anyway, the short description of function `error()` says, "Returns any
errored state in the transport, throwing an exception if empty."

1. I wish you didn't use this word "transport" as a noun. It always
confuses me. Do you mean "either `option` or `resutl` or `outcome`"?

2. "any errored state"? -- not the specific error state previously set
inside `outcome`?

3. It does not mention your algorithm: if `has_value() == true`, returns a
value-initialized error code; if `has_exception() == true`, returns
`error_type((int) monad_errc::exception_present, monad_category())`

4. "Throwing exception if empty" -- what exception?

> > The last case is neither a value, nor a reason for failure, nor an
> > "internal error". How should a caller interpret it? Two possible answers:
> >
> > 1. There is a fourth state with no intuitive or sane interpretation.
> > 2. Assume this never happens. If it happens it is a bug in calle site
> that
> > needs to be fixed.
> You've got to remember all these potential state flow paths never occur
> in any real world code base. You'll even see the compiler eliding in the
> assembler output any handling of an empty state being returned if it can
> see that that is not possible.
> Same goes for if you return only ever a value. The result<T> effectively
> "disappears" in the assembler generated, and it is as if you returned a
> T directly.

I trust you that all these additional guarntees cost nothing at run-time.
My concerns are not really about a potential run-time overhead, but about
what is a correct usage of the library and what is a buggy usage. For
instance, if you changed the semantics of function `error()` to:

Requires: `has_error() == true`.
Returns: the error_code stored in `*this`.

This would make the understanding of the interface simple, it would clearly
indicate when the users do something wrong, you could still implement your
"rescue semantics", but I when I am doing the code review for my
colleagues, I have something objective to rely on: "hey, you are breaking
the precondition, you are extracting the error even though it is not
there". Now, with the rescue semantics, I cannot say a word in the code
review because the other programmer will respond, "But I learned the
detailed rescue semantics, and I figured out it is exactly what I need."
<-- the code does what the programmer intended, but is difficult to
maintain, because it relies on the rescue semantics.

By "rescue semantics" I mean, "id you do not have an error_code to return,
just fabricate one".


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