Boost logo

Boost :

Subject: Re: [boost] [outcome] Possible extensions/changes to std::experimental::expected
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-05-25 21:12:35


It looks like part of the discussion accidentally went into a private
conversation. So, here we are back.

2017-05-25 22:39 GMT+02:00 Vicente J. Botet Escriba <
vicente.botet_at_[hidden]>:

> Le 25/05/2017 à 18:40, Andrzej Krzemienski a écrit :
>
>
>
> 2017-05-25 17:32 GMT+02:00 Vicente J. Botet Escriba <
> vicente.botet_at_[hidden]>:
>
>> Le 25/05/2017 à 13:18, Andrzej Krzemienski via Boost a écrit :
>>
>>> 2017-05-25 9:44 GMT+02:00 Vicente J. Botet Escriba via Boost <
>>> boost_at_[hidden]>:
>>>
>>> We have now the possibility for uninitialized variables, but static
>>> analysis tools will help here.
>>>
>>> So, more specifically, I understand that you propose the following:
>>>
>>> - Default constructor works: no T or no E is construced (similar what
>>> outcome<> does)
>>>
>> I was not aware of this. Do you know that from this reference
>> documentation?
>>
>> constexpr outcome () noexcept(is_nothrow_default_constructible)
>> Default constructor.
>>
>
> Well, I just assumed that since outcome<> has this empty state, it is
> exactly for the purpose of giving semantics to the default constructor. But
> now that you have asked, I looked at the docs. They say nothing about what
> happens in the default constructor. I tried to look in the code, but was
> confused with these policies. So, I just run a small test program, and yes:
> default constructor creates an empty state.
>
> Niall, please could you add an issue in order to document default
> constructors (if it doesn't already exists).
>

This is already logged in https://github.com/ned14/boost.outcome/issues/26

>
>
>>
>> Sorrty, I couldn't interpret it as you.
>> But, if it is the case, yes, as outcome does.
>>
>>> - You can assing to and and destroy such an objetc (similar what
>>> outcome<> does)
>>>
>> I don't catch what you mean here. Are you referring to the conversion
>> between expected with convertible value type and error types?
>>
>
> No, I am saying that the following should work:
> outcome<T> o; // default-constructed
> o = some_outcome<T>(); // this should be safe to execute
>
> This works already with expected even if it doesn't defaults to empty.
>

Ok, and you expect it to continue to work.

>
>
>> - You will probably need to add an observer function that checks for
>>> this singular state, like `is_singular()`. If not for anything else
>>> it
>>> would be used for assisting the static analysis tools. (again,
>>> similar what
>>> outcome<> does)
>>>
>> No. There will be no such observer. This is essential. There is no
>> visible empty state.
>> Or do you consider that chrono::duration should tell you if it was
>> initialized or not?
>> The user know if it is initialized or not, but there is no tool to check
>> it.
>> This could be against safe programming, but we are here in C++ and we
>> should provide first the raw tools and then build on top of them when we
>> want more.
>>
>>> - other observer functions (has_value(), value(), has_error(),
>>> error())
>>> cause UB when `is_singular() == true. (this is the only difference
>>> from
>>> outcome<>)
>>>
>> Not the only one.
>> outcome fixes its error types. I'm proposing an extension to the current
>> expected so that it can take care of the Outcome use cases and needs.
>>
>>>
>>> Did I understand your intentions correctly?
>>>
>> Not completly. I don't want an observer that tells me, attention you have
>> not initialized your variable, or you have moved from. This is essential.
>
>
> Very daring. It would be easier to accept if you could show a tool that is
> capable of statically analying this kind of "used unintialized" bug for
> `expected`.
>
>
> Static analysis to check if uninitialized variables are used (read) works
> very well already . I don't remember if it si with clang-tidy that I have
> seen this kind of warnings.
>

Ok. Now I am thinking, another thing you can do, is to internally store
something like varient<T, Y, Empty> but do not expose this Empty in the
interface. Instead, rewrite observer functions like this:

```
bool has_value() const
{
  if (BOOST_UNLIKELY(_is_in_empty_state()))
    __builtin_unreachable();

  return _is_in_valued_state;
}
```


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