|
Boost : |
Subject: Re: [boost] [outcome] Ternary logic -- need an example
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2017-05-21 13:33:17
Le 20/05/2017 à 23:28, Andrzej Krzemienski via Boost a écrit :
> 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:
> https://ned14.github.io/boost.outcome/structboost_1_1outcome_1_1v1__xxx_1_1policy_1_1monad__policy__base.html#a6d5a06127d3ab8aa317635cfef1ada6a
>
> (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".
>
+1 for all
Vicente
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk