Outcome v2 is feature complete

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Outcome v2 is feature complete

Boost - Dev mailing list
I am pleased to announce that Outcome v2, rewritten to fulfil the Boost
peer review feedback from two months ago, has reached feature
completeness. Outcome provides a STL-quality `result<T, EC>` and an
`outcome<T, EC, E>` implementation of success|failure value transports,
and is expected to pass a second Boost peer review and be submitted for
C++ standardisation as the lowest level of an overall framework as
proposed by:

* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0650r0.pdf
C++ Monadic interface

* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r2.pdf A
proposal to add a utility class to represent expected object (Revision 4)

The idea is that result/outcome are the extremely lightweight
struct-like success|failure value transports suitable for usage in
public APIs, whereas expected is the much richer variant-like monadic
success|failure value transports, and everything participates together
under P0650R0.

A detailed changelog over v1 can be found at
https://github.com/ned14/outcome/blob/master/Readme.md. The main changes
are the removal of lots of stuff which was in v1, and we now replicate
`std::variant<...>` constructor API. v2 is an “absolute bare minimum”
implementation with no frills.

Outcome v2 is passing the modified v1 test suite handily, and v1 code
should port to v2 easily enough. But as an all-new codebase it lacks:

* Maturity
* Polish
* Use experience
* Documentation (a class synopsis can be found at
https://ned14.github.io/outcome/synopsis/)

My hope is to return Outcome v2 for Boost peer review by October. If you
are using an internal Expected-like object, or Outcome v1, I’d hugely
appreciate it if you tried porting your code to using v2 and giving me
feedback on how it went for you. Minimum compilers needed are GCC 6 or
clang 4. Help with documentation and testing is also hugely appreciated.
My thanks in advance!

Github: https://github.com/ned14/outcome

Docs (highly incomplete): https://ned14.github.io/outcome/

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
On Mon, Jul 10, 2017 at 6:32 AM, Niall Douglas via Boost
<[hidden email]> wrote:
> Github: https://github.com/ned14/outcome

What is the quickcpplib submodule in include/outcome for? Is that a
public interface?

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
On 10/07/2017 14:33, Vinnie Falco via Boost wrote:
> On Mon, Jul 10, 2017 at 6:32 AM, Niall Douglas via Boost
> <[hidden email]> wrote:
>> Github: https://github.com/ned14/outcome
>
> What is the quickcpplib submodule in include/outcome for? Is that a
> public interface?

QuickCppLib is the new name for the boost-lite internal sublibrary. Lots
of changes have happened there since the Boost peer review too, mostly
stuff has been removed.

Standalone Outcome will be retaining the use of QuickCppLib as it
provides so much common infrastructure. Eventual script generated
Boost.Outcome will have no git submodules, as per peer review feedback.

Script generated Boost.Outcome is a while out however. Need some
maturation on this library first (at least three months).

Someone on Reddit asked for a single header file edition which you can
drop in. That's being tracked at
https://github.com/ned14/outcome/issues/55, should be implemented very soon.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
On 07/10/17 18:04, Niall Douglas via Boost wrote:

> On 10/07/2017 14:33, Vinnie Falco via Boost wrote:
>> On Mon, Jul 10, 2017 at 6:32 AM, Niall Douglas via Boost
>> <[hidden email]> wrote:
>>> Github: https://github.com/ned14/outcome
>>
>> What is the quickcpplib submodule in include/outcome for? Is that a
>> public interface?
>
> QuickCppLib is the new name for the boost-lite internal sublibrary. Lots
> of changes have happened there since the Boost peer review too, mostly
> stuff has been removed.
>
> Standalone Outcome will be retaining the use of QuickCppLib as it
> provides so much common infrastructure. Eventual script generated
> Boost.Outcome will have no git submodules, as per peer review feedback.
>
> Script generated Boost.Outcome is a while out however. Need some
> maturation on this library first (at least three months).

What version of the library is being proposed for Boost? Will Boost
version contain submodules?

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
>> Standalone Outcome will be retaining the use of QuickCppLib as it
>> provides so much common infrastructure. Eventual script generated
>> Boost.Outcome will have no git submodules, as per peer review feedback.
>>
>> Script generated Boost.Outcome is a while out however. Need some
>> maturation on this library first (at least three months).
>
> What version of the library is being proposed for Boost? Will Boost
> version contain submodules?

As it literally said above, script generated Boost.Outcome will have no
git submodules, as per peer review feedback.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
On 07/10/17 20:35, Niall Douglas via Boost wrote:

>>> Standalone Outcome will be retaining the use of QuickCppLib as it
>>> provides so much common infrastructure. Eventual script generated
>>> Boost.Outcome will have no git submodules, as per peer review feedback.
>>>
>>> Script generated Boost.Outcome is a while out however. Need some
>>> maturation on this library first (at least three months).
>>
>> What version of the library is being proposed for Boost? Will Boost
>> version contain submodules?
>
> As it literally said above, script generated Boost.Outcome will have no
> git submodules, as per peer review feedback.

Oh, sorry, I must have misread that.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
On 10/07/2017 18:41, Andrey Semashev via Boost wrote:

> On 07/10/17 20:35, Niall Douglas via Boost wrote:
>>>> Standalone Outcome will be retaining the use of QuickCppLib as it
>>>> provides so much common infrastructure. Eventual script generated
>>>> Boost.Outcome will have no git submodules, as per peer review feedback.
>>>>
>>>> Script generated Boost.Outcome is a while out however. Need some
>>>> maturation on this library first (at least three months).
>>>
>>> What version of the library is being proposed for Boost? Will Boost
>>> version contain submodules?
>>
>> As it literally said above, script generated Boost.Outcome will have no
>> git submodules, as per peer review feedback.
>
> Oh, sorry, I must have misread that.

As a little added detail, there is now a macro layer in config.hpp which
abstracts out all quickcpplib usage. The script generated Boost.Outcome
will set those macros to Boost equivalents to quickcpplib facilities.
quickcpplib can thus be eliminated in the Boost edition.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Niall Douglas wrote:

> Github: https://github.com/ned14/outcome
>
> Docs (highly incomplete): https://ned14.github.io/outcome/

This is a welcome development, if still a bit too-policy-heavy for my taste.

Regarding construction, I have the following suggestion.

Instead of reusing in_place_type, use the following tag types:

struct in_place_value_t
{
    constexpr in_place_value_t() noexcept {}
};

constexpr in_place_value_t in_place_value;

struct in_place_error_t
{
    constexpr in_place_error_t() noexcept {}
};

constexpr in_place_error_t in_place_error;

This is isomorphic but superior to using in_place_index<0> and
in_place_index<1>, which were my initial choice. Now the ambiguity when T ==
EC is resolved and

template<class... A> result( in_place_value_t, A&&... a );

always initializes the value and does not need to be disabled when T == EC.

In addition, I would add

template<class... A> result( A&&... a );

which initializes the value when it's constructible from a..., the error
when that's constructible from a..., and is disabled when neither or both
are constructible. (The implicit/explicit duality when sizeof...(A) == 1
complicates the actual implementation of the above but conceptually it still
works as explained. Also, the sizeof...(A) == 0 case needs to be disabled.)


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
>> Github: https://github.com/ned14/outcome
>>
>> Docs (highly incomplete): https://ned14.github.io/outcome/
>
> This is a welcome development, if still a bit too-policy-heavy for my
> taste.

The policy is there purely to say what to do when you call .value() on a
non-valued result/outcome. Compelling use cases could be:

- Delay constructing metadata to accompany any exception throws.
- Use .error() as a key to look up an associative map.
- Invoke Emil's Noexcept instead :)

One could have used ADL customisation points instead, but those tend to
surprise end users, so I felt the policy approach was better and leave
the ADL points for advanced users.

> Regarding construction, I have the following suggestion.
>
> Instead of reusing in_place_type, use the following tag types:
>
> struct in_place_value_t
> {
>    constexpr in_place_value_t() noexcept {}
> };
>
> constexpr in_place_value_t in_place_value;
>
> struct in_place_error_t
> {
>    constexpr in_place_error_t() noexcept {}
> };
>
> constexpr in_place_error_t in_place_error;
>
> This is isomorphic but superior to using in_place_index<0> and
> in_place_index<1>, which were my initial choice. Now the ambiguity when
> T == EC is resolved and
>
> template<class... A> result( in_place_value_t, A&&... a );
>
> always initializes the value and does not need to be disabled when T == EC.

You've struck on a very interesting design point indeed, and one which
caused me a few restless nights.

My initial approach was to do exactly what you just described, after all
it's how v1 implemented its tagged emplacing constructors, and v1 had a
host of make_(valued|errored|excepted)_*() functions too. v1's API was
all about construction of specific, named state.

But upon further reflection - and I want to emphasise that I think the
jury is still out on this decision, and I may revert during the next few
months - I decided that std::variant<> by-type emplacement was superior,
so I went with that instead.

The reason why is subtle. These types, result & outcome, are not in the
same use space as Expected where expected<int, int> is perfectly
reasonable due to its use case as a monad. result & outcome are
specifically intended to be used for one thing and one thing only:
returning value *or* error from functions.

And for that one use case, result<int, int> makes no sense. Actually,
it's stronger than that: result<int, int> must **NOT** make sense.
Everything about the API and contract must loudly proclaim that
"ambiguous success and failure types are discouraged" because the type
system should be set up to reflect the non-ambiguity of success vs failure.

Now, we don't ban in place construction of ambiguous success and failure
types because sometimes you are facing code you didn't write yourself,
and you have to deal with it. So you make it possible. But you do make
the programmer type a lot more. You make it annoying.

> In addition, I would add
>
> template<class... A> result( A&&... a );
>
> which initializes the value when it's constructible from a..., the error
> when that's constructible from a..., and is disabled when neither or
> both are constructible. (The implicit/explicit duality when sizeof...(A)
> == 1 complicates the actual implementation of the above but conceptually
> it still works as explained. Also, the sizeof...(A) == 0 case needs to
> be disabled.)

The reason I kept to single argument converting constructors is that I
felt that the added gain of not having to type in_place_type<> was not
worth the additional compile time load. Also variadic templates are slow :(

And finally, std::variant doesn't implement multiple argument converting
constructors. And I figured WG21 know what they're doing.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
2017-07-11 16:09 GMT+02:00 Niall Douglas via Boost <[hidden email]>:

> >> Github: https://github.com/ned14/outcome
> >>
> >> Docs (highly incomplete): https://ned14.github.io/outcome/
> >
> > This is a welcome development, if still a bit too-policy-heavy for my
> > taste.
>
> The policy is there purely to say what to do when you call .value() on a
> non-valued result/outcome. Compelling use cases could be:
>
> - Delay constructing metadata to accompany any exception throws.
> - Use .error() as a key to look up an associative map.
> - Invoke Emil's Noexcept instead :)
>
> One could have used ADL customisation points instead, but those tend to
> surprise end users, so I felt the policy approach was better and leave
> the ADL points for advanced users.
>
> > Regarding construction, I have the following suggestion.
> >
> > Instead of reusing in_place_type, use the following tag types:
> >
> > struct in_place_value_t
> > {
> >    constexpr in_place_value_t() noexcept {}
> > };
> >
> > constexpr in_place_value_t in_place_value;
> >
> > struct in_place_error_t
> > {
> >    constexpr in_place_error_t() noexcept {}
> > };
> >
> > constexpr in_place_error_t in_place_error;
> >
> > This is isomorphic but superior to using in_place_index<0> and
> > in_place_index<1>, which were my initial choice. Now the ambiguity when
> > T == EC is resolved and
> >
> > template<class... A> result( in_place_value_t, A&&... a );
> >
> > always initializes the value and does not need to be disabled when T ==
> EC.
>
> You've struck on a very interesting design point indeed, and one which
> caused me a few restless nights.
>
> My initial approach was to do exactly what you just described, after all
> it's how v1 implemented its tagged emplacing constructors, and v1 had a
> host of make_(valued|errored|excepted)_*() functions too. v1's API was
> all about construction of specific, named state.
>
> But upon further reflection - and I want to emphasise that I think the
> jury is still out on this decision, and I may revert during the next few
> months - I decided that std::variant<> by-type emplacement was superior,
> so I went with that instead.
>
> The reason why is subtle. These types, result & outcome, are not in the
> same use space as Expected where expected<int, int> is perfectly
> reasonable due to its use case as a monad. result & outcome are
> specifically intended to be used for one thing and one thing only:
> returning value *or* error from functions.
>
> And for that one use case, result<int, int> makes no sense. Actually,
> it's stronger than that: result<int, int> must **NOT** make sense.
> Everything about the API and contract must loudly proclaim that
> "ambiguous success and failure types are discouraged" because the type
> system should be set up to reflect the non-ambiguity of success vs failure.
>

maybe result<int, int> indeed looks suspicious, but using
result<error_code, error_code> might come as quite natural:

auto select_first_error(vector<error_code> v)
  -> result<error_code>
{
  if (!v.empty())
    return result<error_code>{in_place_index<0>, v[0]};
  else
    return result<error_code>{in_place_index<1>, MyErrc::NoFirstElement};
}

Regards,
&rzej;

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
Andrzej Krzemienski wrote:

> maybe result<int, int> indeed looks suspicious, but using
> result<error_code, error_code> might come as quite natural:
>
> auto select_first_error(vector<error_code> v)
>   -> result<error_code>
> {
>   if (!v.empty())
>     return result<error_code>{in_place_index<0>, v[0]};
>   else
>     return result<error_code>{in_place_index<1>, MyErrc::NoFirstElement};
> }

Yes, and the next logical step is to look at those magic constants 0 and 1
and say, hey, why not name these, would help readability.

if( !v.empty() )
{
    return { in_place_value, v[0] };
}
else
{
    return { in_place_error, MyErrc::NoFirstElement };
}

Re the multi-arg constructor, one obvious use case is this:

    return { errno, std::generic_category() };

or

    return { GetLastError(), std::system_category() };

although the main purpose is to forward arguments to custom ECs.

I'm working on a prototype that showcases these but it's not ready yet.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Niall Douglas wrote:

> And finally, std::variant doesn't implement multiple argument converting
> constructors. And I figured WG21 know what they're doing.

Some design features translate between similar but different classes, and
some do not. variant<T...> has no idea what the alternatives are or what
they represent, which is reflected in the way it treats them. So you use
in_place_index<3> for the fourth alternative, for example.

In our case, there are only two alternatives and they have known semantics.
This both allows us to use named tags instead of generic type/index based
ones, and it also makes it possible for a human to perform overload
resolution in his mind (due to there being only two options) when faced with
{ x, y, z }.

> Also variadic templates are slow :(

If that's the problem, you could use

    template<class A1, class A2, class... A>
        result( A1&& a1, A2&& a2, A&&... a );

which would be rejected immediately in the one-arg case and hence shouldn't
affect its compile times. I SFINAE on sizeof...(A) >= 2 instead, but I might
switch.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 11/07/2017 15:41, Peter Dimov via Boost wrote:
> Andrzej Krzemienski wrote:
>
>> maybe result<int, int> indeed looks suspicious, but using
>> result<error_code, error_code> might come as quite natural:

An excellent example of what we want to strongly discourage.

I really strongly believe that for result and outcome, you must avoid
choosing types for success and failure which are not very obviously
distinct.

> Re the multi-arg constructor, one obvious use case is this:
>
>    return { errno, std::generic_category() };
>
> or
>
>    return { GetLastError(), std::system_category() };
>
> although the main purpose is to forward arguments to custom ECs.
>
> I'm working on a prototype that showcases these but it's not ready yet.

That you showed above was my biggest motivator in favour of multi-arg
converting constructors.

But countering it, the syntax is unfortunately similar to aggregate
initialisation which is probably why std::variant doesn't allow it. I'd
be interested if someone from WG21 could tell us actually.

And besides, just prefixing the braces with 'std::error_code' means your
code compiles as intended on Outcome v2. I'm all for eliminating
boilerplate, but it does depend at what cost.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
>> And finally, std::variant doesn't implement multiple argument
>> converting constructors. And I figured WG21 know what they're doing.
>
> Some design features translate between similar but different classes,
> and some do not. variant<T...> has no idea what the alternatives are or
> what they represent, which is reflected in the way it treats them. So
> you use in_place_index<3> for the fourth alternative, for example.

I don't understand. variant<...> knows exactly what the alternatives
are. It surely would be straightforward to look at some Arg&&...
sequence and do std::is_constructible<X, Arg&&...> matching against all
possible variant states. The fact they don't do it I surely think is a
deliberate and intentional design choice for some hopefully good reason.

> In our case, there are only two alternatives and they have known
> semantics.

Actually, they don't have known semantics. We don't know anything about
them. The concept pattern matching machinery *may* give them known
semantics, but result/outcome don't know anything about that at the
constructor level.

>> Also variadic templates are slow :(
>
> If that's the problem, you could use
>
>    template<class A1, class A2, class... A>
>        result( A1&& a1, A2&& a2, A&&... a );
>
> which would be rejected immediately in the one-arg case and hence
> shouldn't affect its compile times. I SFINAE on sizeof...(A) >= 2
> instead, but I might switch.

Oh good idea. Logged to https://github.com/ned14/outcome/issues/56

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Niall Douglas wrote:

> But countering it, the syntax is unfortunately similar to aggregate
> initialisation which is probably why std::variant doesn't allow it. I'd be
> interested if someone from WG21 could tell us actually.

I don't remember variant ever having such constructors proposed, but I may
be misremembering.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Niall Douglas wrote:

> I don't understand. variant<...> knows exactly what the alternatives are.

It doesn't know what they mean though. Doesn't know that T1 is the value and
T2 is the error.

> It surely would be straightforward to look at some Arg&&... sequence and
> do std::is_constructible<X, Arg&&...> matching against all possible
> variant states.

The one-argument variant constructor performs overload resolution across all
alternatives and chooses the best match (if one exists.)

This makes it possible for it to sometimes surprise the user with its
choice.

Extending this to multiple arguments would be possible in principle, but
it's not that straightforward as you make it seem. It's not just a matter of
checking is_constructible. You need to choose the best match.

> The fact they don't do it I surely think is a deliberate and intentional
> design choice for some hopefully good reason.

I'm not so sure.

`variant` is very tricky to specify, and from a certain point on, people
were so tired of the endless discussions that they shot any new suggestion
down regardless of merits if it had the potential to generate further
controversy.

I don't remember this even being proposed, but had it been proposed, it
would probably have been rejected summarily without any deliberation,
because it's pretty subtle.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
>> But countering it, the syntax is unfortunately similar to aggregate
>> initialisation which is probably why std::variant doesn't allow it.
>> I'd be interested if someone from WG21 could tell us actually.
>
> I don't remember variant ever having such constructors proposed, but I
> may be misremembering.

That's surprising. They're a very obvious thing to propose, not such an
obvious thing to reject.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
Niall Douglas wrote:
> > I don't remember variant ever having such constructors proposed, but I
> > may be misremembering.
>
> That's surprising. They're a very obvious thing to propose, not such an
> obvious thing to reject.

Agustín Bergé (who still doesn't get the list e-mails) says that he's
positive that this constructor has never been proposed.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
>> I don't understand. variant<...> knows exactly what the alternatives are.
>
> It doesn't know what they mean though. Doesn't know that T1 is the value
> and T2 is the error.

Neither do result/outcome. "value" is simply the first item, "error" the
second item.

It's the policy class which gives meaning. And it can choose, legally,
to give them no meaning. For example, one of the policies simply calls
std::terminate for everything :)

(and yes, I may tighten this laxity as use experience is accumulated)

>> It surely would be straightforward to look at some Arg&&... sequence
>> and do std::is_constructible<X, Arg&&...> matching against all
>> possible variant states.
>
> The one-argument variant constructor performs overload resolution across
> all alternatives and chooses the best match (if one exists.)
>
> This makes it possible for it to sometimes surprise the user with its
> choice.
>
> Extending this to multiple arguments would be possible in principle, but
> it's not that straightforward as you make it seem. It's not just a
> matter of checking is_constructible. You need to choose the best match.

I was just about to tell you that you are wrong, and I went to
http://en.cppreference.com/w/cpp/utility/variant/variant only to see
that you are correct.

Outcome does not do this, the converting constructors disable themselves
if there is any ambiguity in what to construct. We don't do overload
resolution, if we had to, we fail to compile.

I am in fact quite surprised - perhaps even shocked - that variant does
that. I'd call that a dangerous behaviour. Anything implicit, hidden,
and non-obvious like that is an unwise design choice. Better to make the
programmer spell out intent when there is a chance of ambiguity.

>> The fact they don't do it I surely think is a deliberate and
>> intentional design choice for some hopefully good reason.
>
> I'm not so sure.
>
> `variant` is very tricky to specify, and from a certain point on, people
> were so tired of the endless discussions that they shot any new
> suggestion down regardless of merits if it had the potential to generate
> further controversy.

:(

> I don't remember this even being proposed, but had it been proposed, it
> would probably have been rejected summarily without any deliberation,
> because it's pretty subtle.

:( :(

This is why we don't rush design-by-committee things into the C++
standard. I'm really shocked about that overload resolution design
decision. That's such an unwise choice given the available alternatives.

Anyway I think you've persuaded me on issue #56. Great idea on the
two-arg form.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Outcome v2 is feature complete

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
> If that's the problem, you could use
>
>    template<class A1, class A2, class... A>
>        result( A1&& a1, A2&& a2, A&&... a );
>
> which would be rejected immediately in the one-arg case and hence
> shouldn't affect its compile times. I SFINAE on sizeof...(A) >= 2
> instead, but I might switch.

Ok, these are now implemented in develop branch with test cases. Appear
to work well and no measurable effects on compile times thanks to the
two arg form. Thanks for the idea Peter.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Loading...