Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add structured bindings compatibility #164

Open
ned14 opened this issue Jan 16, 2019 · 5 comments
Open

Add structured bindings compatibility #164

ned14 opened this issue Jan 16, 2019 · 5 comments

Comments

@ned14
Copy link
Owner

ned14 commented Jan 16, 2019

For some odd reason, some odd people want to write:

[has_error, value, error] = func(...);

... where func() returns result<T, E>.

Implementing this is trivial: specialise tuple_size<basic_result<>> to return 3 and implement at<I>(). But I suspect given the dragging in of <tuple>, this support needs its own header file outside the standard set of inclusions.

@akrzemi1
Copy link
Collaborator

There seems something wrong with this idea. Structured bindings are designed to work with product types, like aggregates, arrays, tuples. Whereas result<T, E> is a sum type, much like variant. You do not do structure bindings on variant. Similarly, I do not see how it could work on result<>:

auto r [has_error, val, error] = result<int, Error>{failure(Error::BadInput)};

What value does val have?

@ned14
Copy link
Owner Author

ned14 commented Jan 16, 2019

Well, I was just responding to an email there where the bloke pointed out that result is not a sum type, but is really a tuple and ought to quack like one. And he wants structured bindings on it. And he made lots of arguments about how pretty the code looks etc, specifically that typing .value() and .error() all the time is clumsy and litters the screen unnecessarily.

In the end, I can't marshal a technical argument against it. A structured bindings interface is safe to use. And I do see how some would find the code looks cleaner.

To answer your question, the structured bindings interface would only be available for result and outcome types whose value, error and exception types all have default constructors. So:

auto [has_error, val, error] = result<int, Error>{failure(Error::BadInput)};

... would set has_error to true (bool), val to 0 (int) and error to Error::BadInput (Error).

@akrzemi1
Copy link
Collaborator

Maybe inside the implementation it is a tuple. But at the interface level it is a variant.

I acknowledge that it is implementable for a subset of instantiations of result<T, E>. But at the same time it is somewhat counter to the spirit of the library. It allows you too easily to use a value that is not a value and en error that is not an error.

I am interested to see the examples that illustrate the usefulness. Maybe what would be useful instead is a pattern matching interface:

match(func(...),
           [](auto&& val) { /* use val */ },
           [](auto&& error) { /* use error */ }
);

@ned14
Copy link
Owner Author

ned14 commented Jan 17, 2019

It allows you too easily to use a value that is not a value and en error that is not an error.

Could we make the provision of structured bindings no-value policy determined? So, if the no-value policy is hard UB, that seems much more fine to me to permit structured bindings. If the no-value policy is throw on access of valueless, then structured bindings would not be available by default.

This would preserve the spirit of the library I think.

Regarding matching, absolutely yes please to that. But I think it should be its own library, made generic and reusable. I also think it's easy to do something nice for a limited use set. I think it's hard to design something elegant which is highly reusable. Or put another way, I don't want to start such a design until at least 2020 given my current work queue.

@DBJDBJ
Copy link

DBJDBJ commented Oct 12, 2019

How about this?

       auto [ val, stat ] = my_fun() ;

      if ( ! val  && ! stat ) then  { /* empty */}
      if ( ! val  &&    stat ) then  { /* error   */}
      if (   val  &&  ! stat ) then  { /*  ok      */}
      if (   val  &&    stat ) then  { /*  info    */}

Kind regards ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants