[gsoc-2013] Boost.Expected
Hello,
My name is Pierre Talbot, I participated to GSoC 2011 and began the
implementation of the Boost.Check library (for checking the validity of
any number having a check digit — credit card number, ISBN, …). It was
two years ago and the design is still evolving due to many variation
points in the code. One of the function looks like :
template
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
I can code a "proof of concept" if you think this is a good idea.
I'm willing to test it in real application if you make an implementation. I think it is necessary to check the usability of this kind of library directly in practice instead of pondering based on assumptions. It's hard to figure out the side effects or using this tool. (at least to me)
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: I can code a "proof of concept" if you think this is a good idea.
I'm willing to test it in real application if you make an implementation. I think it is necessary to check the usability of this kind of library directly in practice instead of pondering based on assumptions. It's hard to figure out the side effects or using this tool. (at least to me) Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html Note: In the example folder, the "b2" command never terminates (but correctly generates binaries), I can't figure out why. Please, do not hesitate to give me advices and critics to improve this library and my future proposal. Thank you, Pierre Talbot.
AMDG On 04/19/2013 07:36 AM, Pierre T. wrote:
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Note: In the example folder, the "b2" command never terminates (but correctly generates binaries), I can't figure out why.
Is any subprocess still running? b2 doesn't print any output for a command until it finishes (to avoid interleaving for parallel builds), so the last output is an action that has completed successfully, /not/ the action that is currently running. What platform is this on?
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
In Christ, Steven Watanabe
On 04/19/2013 05:01 PM, Steven Watanabe wrote:
AMDG
On 04/19/2013 07:36 AM, Pierre T. wrote:
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Note: In the example folder, the "b2" command never terminates (but correctly generates binaries), I can't figure out why.
Is any subprocess still running? b2 doesn't print any output for a command until it finishes (to avoid interleaving for parallel builds), so the last output is an action that has completed successfully, /not/ the action that is currently running. What platform is this on? I'm not sure what you mean with "subprocess", only the b2 command is returned by "ps -a | grep b2". Here the output of b2 :
...found 31 targets... ...updating 15 targets... common.mkdir bin common.mkdir bin/expected_or_error_example.test common.mkdir bin/expected_or_error_example.test/gcc-4.7 common.mkdir bin/expected_or_error_example.test/gcc-4.7/debug gcc.compile.c++ bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example.o gcc.link bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example ^C I'm on Linux (Ubuntu). But on this same platform, I already successful run bjam with another project. Thanks for help, Pierre Talbot.
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
In Christ, Steven Watanabe
Le 19/04/13 17:21, Pierre T. a écrit :
On 04/19/2013 05:01 PM, Steven Watanabe wrote:
AMDG
On 04/19/2013 07:36 AM, Pierre T. wrote:
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Note: In the example folder, the "b2" command never terminates (but correctly generates binaries), I can't figure out why.
Is any subprocess still running? b2 doesn't print any output for a command until it finishes (to avoid interleaving for parallel builds), so the last output is an action that has completed successfully, /not/ the action that is currently running. What platform is this on? I'm not sure what you mean with "subprocess", only the b2 command is returned by "ps -a | grep b2". Here the output of b2 :
...found 31 targets... ...updating 15 targets... common.mkdir bin common.mkdir bin/expected_or_error_example.test common.mkdir bin/expected_or_error_example.test/gcc-4.7 common.mkdir bin/expected_or_error_example.test/gcc-4.7/debug gcc.compile.c++ bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example.o gcc.link bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example ^C
I'm on Linux (Ubuntu). But on this same platform, I already successful run bjam with another project.
I suspect that your program is expecting you give the password, but when you use b2 you can not even see the request for it. Steve is there a way to give a file as input to the test? How we should bjam setup this kind of examples so that we can interact with stdin/stdout? Best, Vicente Best, Vicente
AMDG On 04/19/2013 10:03 AM, Vicente J. Botet Escriba wrote:
Le 19/04/13 17:21, Pierre T. a écrit :
gcc.link bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example
^C
I'm on Linux (Ubuntu). But on this same platform, I already successful run bjam with another project.
I suspect that your program is expecting you give the password, but when you use b2 you can not even see the request for it. Steve is there a way to give a file as input to the test?
How we should bjam setup this kind of examples so that we can interact with stdin/stdout?
Programs run under a build tool should not require any action from the user. You could try redirecting stdin like this: path-constant input-file : input.txt ; run mytest.cpp : < \"$(input-file)\" ; I haven't tested whether this actually works, though. In Christ, Steven Watanabe
Le 19/04/13 19:37, Steven Watanabe a écrit :
AMDG
On 04/19/2013 10:03 AM, Vicente J. Botet Escriba wrote:
Le 19/04/13 17:21, Pierre T. a écrit :
gcc.link bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example
^C
I'm on Linux (Ubuntu). But on this same platform, I already successful run bjam with another project.
I suspect that your program is expecting you give the password, but when you use b2 you can not even see the request for it. Steve is there a way to give a file as input to the test?
How we should bjam setup this kind of examples so that we can interact with stdin/stdout?
Programs run under a build tool should not require any action from the user. Agreed. Should we use instead for these kind of examples just the exe rule and execute the example off-line? You could try redirecting stdin like this:
path-constant input-file : input.txt ; run mytest.cpp : < \"$(input-file)\" ;
I haven't tested whether this actually works, though.
Thanks, I will try it. Vicente
On 04/20/2013 12:33 AM, Vicente J. Botet Escriba wrote:
Le 19/04/13 19:37, Steven Watanabe a écrit :
AMDG
On 04/19/2013 10:03 AM, Vicente J. Botet Escriba wrote:
Le 19/04/13 17:21, Pierre T. a écrit :
gcc.link bin/expected_or_error_example.test/gcc-4.7/debug/expected_or_error_example
^C
I'm on Linux (Ubuntu). But on this same platform, I already successful run bjam with another project.
I suspect that your program is expecting you give the password, but when you use b2 you can not even see the request for it. Steve is there a way to give a file as input to the test?
How we should bjam setup this kind of examples so that we can interact with stdin/stdout?
Programs run under a build tool should not require any action from the user. Agreed. Should we use instead for these kind of examples just the exe rule and execute the example off-line? Good to know. You could try redirecting stdin like this:
path-constant input-file : input.txt ; run mytest.cpp : < \"$(input-file)\" ;
I haven't tested whether this actually works, though.
Thanks, I will try it. Vicente
I removed the std::cin instruction and replace it with a string array, it works now :-) If you have any other comments, please let me know. Thanks. Pierre T.
Le 19/04/13 16:36, Pierre T. a écrit :
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: I can code a "proof of concept" if you think this is a good idea.
I'm willing to test it in real application if you make an implementation. I think it is necessary to check the usability of this kind of library directly in practice instead of pondering based on assumptions. It's hard to figure out the side effects or using this tool. (at least to me) Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
Hi, glad to see you are exploring the different alternatives. This is really a good starting point. See attached my draft (not tested) of expected which is based on Alexandrescu class but adapted to boost notation and making it portable to c++98 compilers. In addition I added some additional helper functions. Now it is time to make a concrete proposal for you candidature. Best, Vicente
Le 20/04/13 10:50, Vicente J. Botet Escriba a écrit :
Le 19/04/13 16:36, Pierre T. a écrit :
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
Hi,
glad to see you are exploring the different alternatives. This is really a good starting point.
Now it is time to make a concrete proposal for you candidature.
Hi again, I have some questions: Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't know if the const get function should be provided? const T& get() const { return value; } what do you think? What about an explicit conversion to the underlying type that behaves as the get function? What about an explicit conversion to bool that behaves as the valid function? Do you pretend to provide a C++98 portable implementation? How the expected_or_error behaves in the presence of copy constructor exceptions? Which expected_or_error<> functions can be declared as noexcept? Which expected<> functions can be declared as noexcept? Best, Vicente
On 04/20/2013 11:36 AM, Vicente J. Botet Escriba wrote:
Le 20/04/13 10:50, Vicente J. Botet Escriba a écrit :
Le 19/04/13 16:36, Pierre T. a écrit :
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
Hi,
glad to see you are exploring the different alternatives. This is really a good starting point.
Now it is time to make a concrete proposal for you candidature.
Hi again,
Hi,
I have some questions:
Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't have any use cases where expected/expected_or_error would have value semantics. Even if the underlying value has value semantics, you can't compare exceptions and you rarely compare two error code encapsulated into two variables (of course you often compare a variable and a constant error code). So, unless we give me good arguments, I would consider it as entity semantics.
I don't know if the const get function should be provided? const T& get() const { return value; } what do you think? Because expected<> aims to always be a return value, I would be say we don't need it. Nevertheless, the user could pass expected to a function by const-ref. So to enable any programming style, I would let it there.
What about an explicit conversion to the underlying type that behaves as the get function?
Is there really an interest to do (type)e instead of e.get() ? I'm not sure. However I don't have any arguments against it.
What about an explicit conversion to bool that behaves as the valid function? Yes, even an implicit conversion to bool could be useful.
Do you pretend to provide a C++98 portable implementation? I'm pretty sure it's possible with some features disable such as the move semantics. Should we use boost::variant to facilitate the C++98 variant implementation ?
How the expected_or_error behaves in the presence of copy constructor exceptions? It doesn't capture the exception and the responsibility of handling this exception is delegated to higher layer.
Which expected_or_error<> functions can be declared as noexcept?
Constructor/operator=: noexcept if the T/ErrorType copy/move constructor doesn't throw. Destructor: noexcept if the T/ErrorType destructor doesn't throw. Swap: noexcept if the move constructor(c++11)/ copy constructor(c++98) doesn't throw. Observer and getter can be declared as no except.
Which expected<> functions can be declared as noexcept?
Same as above plus: noexcept: fromException(std::exception_ptr p); fromException(); fromCode(F fun);
Best, Vicente
Your questions are interesting and I'm not sure I gave the best answers. Some of the design decisions are hard to guess without any feedback from users (such as the value semantics). I like your implementation of expected, the "then" method is similar to what I tried to achieve with "resolve". Maybe we could have a method "otherwise" which do the same than "then" but with the error ? I'll send soon my proposal to the boost mailing-list for any reviews/comments. Thank you, Pierre Talbot.
Le 20/04/13 14:44, Pierre T. a écrit :
On 04/20/2013 11:36 AM, Vicente J. Botet Escriba wrote:
Le 20/04/13 10:50, Vicente J. Botet Escriba a écrit :
Le 19/04/13 16:36, Pierre T. a écrit :
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
Hi,
glad to see you are exploring the different alternatives. This is really a good starting point.
Now it is time to make a concrete proposal for you candidature.
Hi again,
Hi,
I have some questions:
Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't have any use cases where expected/expected_or_error would have value semantics. Even if the underlying value has value semantics, you can't compare exceptions and you rarely compare two error code encapsulated into two variables (of course you often compare a variable and a constant error code). So, unless we give me good arguments, I would consider it as entity semantics. I was wondering as optional<T> has value semantics and no value is different from any optional valued. I don't know yet if it has a sens to define it for expected_or_error and you are right we need a valid use case.
I don't know if the const get function should be provided? const T& get() const { return value; } what do you think? Because expected<> aims to always be a return value, I would be say we don't need it. Nevertheless, the user could pass expected to a function by const-ref. So to enable any programming style, I would let it there. Sorry, I meant the non-const. Anyway, I guess that it is there to make easier to pass a non-const to a function expecting a T&.
expected<T> r =f(); g(r.get());
What about an explicit conversion to the underlying type that behaves as the get function?
Is there really an interest to do (type)e instead of e.get() ? I'm not sure. However I don't have any arguments against it.
What about an explicit conversion to bool that behaves as the valid function? Yes, even an implicit conversion to bool could be useful.
Hrrr, no please no implicit conversion. After comparing with optional, the problem could also be what the user could expect from expected<bool> b = f(); if (b) {...}
Do you pretend to provide a C++98 portable implementation? I'm pretty sure it's possible with some features disable such as the move semantics.
I would not be able to use it if Boost.Move is not supported.
Should we use boost::variant to facilitate the C++98 variant implementation ? I don't know if boost::variant supports move semantics. I don't think it is worth adding this dependency, but maybe I'm wrong.
How the expected_or_error behaves in the presence of copy constructor exceptions? It doesn't capture the exception and the responsibility of handling this exception is delegated to higher layer.
Stating clearly this behavior in the proposal would be appreciated.
Which expected_or_error<> functions can be declared as noexcept?
Constructor/operator=: noexcept if the T/ErrorType copy/move constructor doesn't throw. Destructor: noexcept if the T/ErrorType destructor doesn't throw. Swap: noexcept if the move constructor(c++11)/ copy constructor(c++98) doesn't throw.
Observer and getter can be declared as no except.
Which expected<> functions can be declared as noexcept?
Same as above plus:
noexcept: fromException(std::exception_ptr p); fromException(); fromCode(F fun);
Could you add them to the scope of the proposal, BTW, could you rename the camelCase function to the usual Boost style, e.g. from_exception. Note that I have removed these functions and replaced them as non-member factories. What do you think?
Best, Vicente
Your questions are interesting and I'm not sure I gave the best answers. Some of the design decisions are hard to guess without any feedback from users (such as the value semantics).
I like your implementation of expected, the "then" method is similar to what I tried to achieve with "resolve". Maybe we could have a method "otherwise" which do the same than "then" but with the error ? Yes sure. It would be great to explore it with specific examples.
I'll send soon my proposal to the boost mailing-list for any reviews/comments.
Great, Vicente
On 04/20/2013 03:14 PM, Vicente J. Botet Escriba wrote:
Le 20/04/13 14:44, Pierre T. a écrit :
On 04/20/2013 11:36 AM, Vicente J. Botet Escriba wrote:
Le 20/04/13 10:50, Vicente J. Botet Escriba a écrit :
Le 19/04/13 16:36, Pierre T. a écrit :
On 04/13/2013 12:57 PM, Klaim - Joël Lamotte wrote:
On Sat, Apr 13, 2013 at 8:38 AM, Pierre T.
wrote: Hello,
I gave a try at the implementation of the expected_or_error class. I used the boost layout to package the implementation, you can download it here : http://www.hyc.io/boost/expected.zip Finally, feel free to explore the documentation I wrote http://www.hyc.io/boost/index.html
Please, do not hesitate to give me advices and critics to improve this library and my future proposal.
Hi,
glad to see you are exploring the different alternatives. This is really a good starting point.
Now it is time to make a concrete proposal for you candidature.
Hi again,
Hi,
I have some questions:
Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't have any use cases where expected/expected_or_error would have value semantics. Even if the underlying value has value semantics, you can't compare exceptions and you rarely compare two error code encapsulated into two variables (of course you often compare a variable and a constant error code). So, unless we give me good arguments, I would consider it as entity semantics. I was wondering as optional<T> has value semantics and no value is different from any optional valued. I don't know yet if it has a sens to define it for expected_or_error and you are right we need a valid use case. Do you say there is a sens to define it for expected ? How do we compare two exceptions ?
I don't know if the const get function should be provided? const T& get() const { return value; } what do you think? Because expected<> aims to always be a return value, I would be say we don't need it. Nevertheless, the user could pass expected to a function by const-ref. So to enable any programming style, I would let it there. Sorry, I meant the non-const. Anyway, I guess that it is there to make easier to pass a non-const to a function expecting a T&.
expected<T> r =f(); g(r.get());
What about an explicit conversion to the underlying type that behaves as the get function?
Is there really an interest to do (type)e instead of e.get() ? I'm not sure. However I don't have any arguments against it.
What about an explicit conversion to bool that behaves as the valid function? Yes, even an implicit conversion to bool could be useful.
Hrrr, no please no implicit conversion. After comparing with optional, the problem could also be what the user could expect from
expected<bool> b = f(); if (b) {...} Right !
Do you pretend to provide a C++98 portable implementation? I'm pretty sure it's possible with some features disable such as the move semantics.
I would not be able to use it if Boost.Move is not supported.
Should we use boost::variant to facilitate the C++98 variant implementation ? I don't know if boost::variant supports move semantics. I don't think it is worth adding this dependency, but maybe I'm wrong.
How the expected_or_error behaves in the presence of copy constructor exceptions? It doesn't capture the exception and the responsibility of handling this exception is delegated to higher layer.
Stating clearly this behavior in the proposal would be appreciated. In fact, we could create an error code class containing a ptr_exception. I'm not really sure what would be the best. Though, I'd stick to the first idea at the moment.
Which expected_or_error<> functions can be declared as noexcept?
Constructor/operator=: noexcept if the T/ErrorType copy/move constructor doesn't throw. Destructor: noexcept if the T/ErrorType destructor doesn't throw. Swap: noexcept if the move constructor(c++11)/ copy constructor(c++98) doesn't throw.
Observer and getter can be declared as no except.
Which expected<> functions can be declared as noexcept?
Same as above plus:
noexcept: fromException(std::exception_ptr p); fromException(); fromCode(F fun);
Could you add them to the scope of the proposal, BTW, could you rename the camelCase function to the usual Boost style, e.g. from_exception. Note that I have removed these functions and replaced them as non-member factories. What do you think?
It's an idea that I really like in your implementation, I prefer the "make_XXX" non-member function. So I'm totally agree with this idea.
Best, Vicente
Your questions are interesting and I'm not sure I gave the best answers. Some of the design decisions are hard to guess without any feedback from users (such as the value semantics).
I like your implementation of expected, the "then" method is similar to what I tried to achieve with "resolve". Maybe we could have a method "otherwise" which do the same than "then" but with the error ? Yes sure. It would be great to explore it with specific examples. I'll add a "otherwise" method in the proposal.
I'll send soon my proposal to the boost mailing-list for any reviews/comments.
Great, Vicente
Thanks for all the comments ! Pierre T.
Le 20/04/13 20:45, Pierre T. a écrit :
On 04/20/2013 03:14 PM, Vicente J. Botet Escriba wrote:
Le 20/04/13 14:44, Pierre T. a écrit :
On 04/20/2013 11:36 AM, Vicente J. Botet Escriba wrote:
Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't have any use cases where expected/expected_or_error would have value semantics. Even if the underlying value has value semantics, you can't compare exceptions and you rarely compare two error code encapsulated into two variables (of course you often compare a variable and a constant error code). So, unless we give me good arguments, I would consider it as entity semantics. I was wondering as optional<T> has value semantics and no value is different from any optional valued. I don't know yet if it has a sens to define it for expected_or_error and you are right we need a valid use case. Do you say there is a sens to define it for expected ? How do we compare two exceptions ? I don't know. We could consider that the exception is not part of the expected class in the same way as we don't take in account an internal mutex when we compare 2 synchronized_value. Comparing two valued expected would rely on the type T, comparing to exceptional expected succeeds always (as if the value was not set) and mixing them fails. The main difference is that here the exception could be visible while in synchronized_value the mutex is hidden.
Let comparison out of the scope of the proposal for the time been. Best, Vicente
On 04/21/2013 09:17 AM, Vicente J. Botet Escriba wrote:
Le 20/04/13 20:45, Pierre T. a écrit :
On 04/20/2013 03:14 PM, Vicente J. Botet Escriba wrote:
Le 20/04/13 14:44, Pierre T. a écrit :
On 04/20/2013 11:36 AM, Vicente J. Botet Escriba wrote:
Do you think that expected and/or expected_or_error could/should have value semantics, that is define operator==? I don't have any use cases where expected/expected_or_error would have value semantics. Even if the underlying value has value semantics, you can't compare exceptions and you rarely compare two error code encapsulated into two variables (of course you often compare a variable and a constant error code). So, unless we give me good arguments, I would consider it as entity semantics. I was wondering as optional<T> has value semantics and no value is different from any optional valued. I don't know yet if it has a sens to define it for expected_or_error and you are right we need a valid use case. Do you say there is a sens to define it for expected ? How do we compare two exceptions ? I don't know. We could consider that the exception is not part of the expected class in the same way as we don't take in account an internal mutex when we compare 2 synchronized_value. Comparing two valued expected would rely on the type T, comparing to exceptional expected succeeds always (as if the value was not set) and mixing them fails. The main difference is that here the exception could be visible while in synchronized_value the mutex is hidden.
Let comparison out of the scope of the proposal for the time been.
Best, Vicente
I think this behavior could lead to potential mis-understanding (and possibly bugs ?) from the user. However, you are right, we'll discuss it later if needed. Best regards, Pierre T.
A few thoughts about expected<> :
I think comparison with optional<> is worthwhile. In fact, I think we
should consider small changes to optional, if necessary, if it helps them
align. Specifically I'm thinking of the cast to bool. Does the below
conversions to bool bother anyone?
std::expected
Hello, On 04/22/2013 06:45 PM, Gottlob Frege wrote:
A few thoughts about expected<> :
I think comparison with optional<> is worthwhile. In fact, I think we should consider small changes to optional, if necessary, if it helps them align. Specifically I'm thinking of the cast to bool. Does the below conversions to bool bother anyone?
std::expected
exp = ...; std::optional<int> opt = ...; if (opt) { ... }
if (exp) { ... }
And if that doesn't bother you, change the 'int' to 'bool' above.
I don't care which way it goes (the alternative being a explicit function call, like exp.valid() or is_valid() or...), but I think it makes sense for expected and optional to work the same way, and currently, optional<> is set to work in the above. So if you really dislike if (exp), then you have an uphill battle to change optional, which was just accepted.
As for comparing "exceptions", I'm not sure the exception part of expected should be always considered an exception. Maybe it is just the "false case" type. ie
expected
or expected or however you want to think of it.
I would only call it an *exception* type if it gets thrown when trying to access the value of a false expected:
You right, we should align on std::optional, at least for the bool cast.
std::expected
exp; int x = exp.value(); // has no value - does this throw bad_expected_access, or does it throw Exception()?
Actually, expected contains an error and we don't know anything about
the type of the error so we cannot throw it. It's what I called
expected_base
I think answering these questions might help answering the comparison questions. ie first know what expected<> really is.
Tony
Should expected be a generic component on the error type such as
Expected
2013/4/23 Pierre T.
Hello, std::expected
exp; int x = exp.value(); // has no value - does this throw bad_expected_access, or does it throw Exception()?
Actually, expected contains an error and we don't know anything about
the type of the error so we cannot throw it. It's what I called expected_base
in my previous mails, the get() on expected_base doesn't throw and if expected_base doesn't contain a value, then undefined behavior occurs.
Hmm, couldn't the original error be thrown anyway (if the wrapping type had a virtual function that would throw the error)? Regards, Kris
On Tue, Apr 23, 2013 at 10:18 AM, Krzysztof Czainski <1czajnik@gmail.com>wrote:
2013/4/23 Pierre T.
Hello, std::expected
exp; int x = exp.value(); // has no value - does this throw bad_expected_access, or does it throw Exception()?
Actually, expected contains an error and we don't know anything about
the type of the error so we cannot throw it.
We can throw anything we want. I'm not sure it is a good idea, but you can throw anything. It doesn't need to derive from std::expection, for example. You can throw an int. etc.
It's what I called
expected_base
in my previous mails, the get() on expected_base doesn't throw and if expected_base doesn't contain a value, then undefined behavior occurs. Hmm, couldn't the original error be thrown anyway (if the wrapping type had a virtual function that would throw the error)?
Regards, Kris
I think we'd like to avoid virtual functions. I'm not even sure the base class is needed. I think we only want one expected<>, not 2 or 3 variants. (Although maybe I don't understand what all the variants are, I haven't looked at it thoroughly.) What we did for optional<> is allow you to access the value in 2 ways: optional<int> oi; int x = oi.value(); // throws bad_optional_access int y = *oi; // undefined behaviour Similar to vector [n] vs at(n). I think expected<> should work the same way. The only question, to me, is what it throws. Either it throws the Error, or it throws bad_expected_access. Or it throws bad_expected_access<Error> which derives from bad_expected_access_base, or something like that. (ie a well defined exception, but I can still get my custom Error value back from it if I want.) Tony
Le 23/04/2013 18:55, Gottlob Frege a écrit :
On Tue, Apr 23, 2013 at 10:18 AM, Krzysztof Czainski <1czajnik@gmail.com>wrote:
2013/4/23 Pierre T.
Hello, std::expected
exp; int x = exp.value(); // has no value - does this throw bad_expected_access, or does it throw Exception()?
Actually, expected contains an error and we don't know anything about
the type of the error so we cannot throw it.
We can throw anything we want. I'm not sure it is a good idea, but you can throw anything. It doesn't need to derive from std::expection, for example. You can throw an int. etc.
Of course, but I guess it's a bad practice ?
It's what I called
expected_base
in my previous mails, the get() on expected_base doesn't throw and if expected_base doesn't contain a value, then undefined behavior occurs. Hmm, couldn't the original error be thrown anyway (if the wrapping type had a virtual function that would throw the error)?
Regards, Kris
I think we'd like to avoid virtual functions. I'm not even sure the base class is needed. I think we only want one expected<>, not 2 or 3 variants. (Although maybe I don't understand what all the variants are, I haven't looked at it thoroughly.)
What we did for optional<> is allow you to access the value in 2 ways:
optional<int> oi;
int x = oi.value(); // throws bad_optional_access int y = *oi; // undefined behaviour
Similar to vector [n] vs at(n).
We could use something similar in expected. But we must keep in mind that expected has a value and an error, is it clear that *expect return the value and not the error ?
I think expected<> should work the same way.
The only question, to me, is what it throws. Either it throws the Error, or it throws bad_expected_access. Or it throws bad_expected_access<Error> which derives from bad_expected_access_base, or something like that. (ie a well defined exception, but I can still get my custom Error value back from it if I want.)
Tony
I guess that the idea of error_wrapper_exception<Error> is interesting. Mainly because it enables us to have an unique variant of expected. However, if Error is an exception, it shouldn't be encapsulated into a error_wrapper_exception. What others think about this behavior and interface ? Thanks for any comments. Pierre Talbot.
On Tue, Apr 23, 2013 at 3:28 PM, Pierre T.
Le 23/04/2013 18:55, Gottlob Frege a écrit :
We can throw anything we want. I'm not sure it is a good idea, but you
can throw anything. It doesn't need to derive from std::expection, for example. You can throw an int. etc.
Of course, but I guess it's a bad practice ?
I'd agree with that.
What we did for optional<> is allow you to access the value in 2 ways:
optional<int> oi;
int x = oi.value(); // throws bad_optional_access int y = *oi; // undefined behaviour
Similar to vector [n] vs at(n).
We could use something similar in expected. But we must keep in mind that expected has a value and an error, is it clear that *expect return the value and not the error ?
Yes. It is called "expected" after all. You expect the value, not the
error. And if there is an expect.is_valid() I expect it to be referring to
whether the value is valid, not the error. Etc. It is not called
"std::pair
I think expected<> should work the same way.
The only question, to me, is what it throws. Either it throws the Error, or it throws bad_expected_access. Or it throws bad_expected_access<Error> which derives from bad_expected_access_base, or something like that. (ie a well defined exception, but I can still get my custom Error value back from it if I want.)
Tony
I guess that the idea of error_wrapper_exception<Error> is interesting. Mainly because it enables us to have an unique variant of expected. However, if Error is an exception, it shouldn't be encapsulated into a error_wrapper_exception.
I don't like special cases, but I can imagine checking at compile time
whether Error derives from std::exception or not. But that means anyone
using their own (non-std) exception hierarchy, expected
What others think about this behavior and interface ?
Thanks for any comments. Pierre Talbot.
I'd definitely like to hear more from others. Maybe I'm not imagining some of the ways this is expected to be used. Tony (all puns are purely intentional.)
On 4/23/13 3:43 PM, Gottlob Frege wrote:
On Tue, Apr 23, 2013 at 3:28 PM, Pierre T.
wrote: Le 23/04/2013 18:55, Gottlob Frege a écrit :
We can throw anything we want. I'm not sure it is a good idea, but you
can throw anything. It doesn't need to derive from std::expection, for example. You can throw an int. etc.
Of course, but I guess it's a bad practice ?
I'd agree with that.
What we did for optional<> is allow you to access the value in 2 ways:
optional<int> oi;
int x = oi.value(); // throws bad_optional_access int y = *oi; // undefined behaviour
Similar to vector [n] vs at(n).
We could use something similar in expected. But we must keep in mind that expected has a value and an error, is it clear that *expect return the value and not the error ?
Yes. It is called "expected" after all. You expect the value, not the error. And if there is an expect.is_valid() I expect it to be referring to whether the value is valid, not the error. Etc. It is not called "std::pair
", it is expected . IMO, at least.
It seems to me that if you're using this expected class, you're expecting an error, at least some times. Otherwise why wouldn't you just throw. FWIW I think the OP's idea of separating out the error handling code from the error site is misguided here. This isn't exceptional flow it's part of the normal expected behavior. If you're using it to parse user input for instance handling invalid input to me seems directly applicable to the task at hand even if it must be propagated a short ways to be handled. .
But I lean towards thinking that Error is rarely or never an exception - if it was, why use expected<> at all? Just throw the exception. I think of expected<> as being used in places where you don't want to use exceptions. ie if you have
expected
someFunction(); where someFunction() could *return* an exception, why not just
int someFunction(); // throws SomeException
So I think I'd prefer it always to wrap. ie assume that the Error is NOT an exception, and not meant to be thrown. The only time it is thrown is when someone (mistakenly? ie coder error) accesses the value via expect.value() and it throws bad_expected_access<Error>. Or "un_expected_access" :-)
Seems a lot like a code error to me. Might as well just throw std::logic_error if you're going to implement the anti-pattern. If you're going to specify what happens at all here you might as well std::terminate. Personally I would prefer leaving the behavior undefined.
What others think about this behavior and interface ?
Thanks for any comments. Pierre Talbot.
I'd definitely like to hear more from others. Maybe I'm not imagining some of the ways this is expected to be used.
I dislike expected's type not encoding what errors it the user should be
expected to handle.
In many ways it seems worse to me than returning a variant like
variant
Le 23/04/13 18:55, Gottlob Frege a écrit :
On Tue, Apr 23, 2013 at 10:18 AM, Krzysztof Czainski <1czajnik@gmail.com>wrote:
2013/4/23 Pierre T.
It's what I called
expected_base
in my previous mails, the get() on expected_base doesn't throw and if expected_base doesn't contain a value, then undefined I would expect an exception. behavior occurs. Hmm, couldn't the original error be thrown anyway (if the wrapping type had a virtual function that would throw the error)?
I think we'd like to avoid virtual functions. I'm not even sure the base class is needed. I think we only want one expected<>, not 2 or 3 variants. (Although maybe I don't understand what all the variants are, I haven't looked at it thoroughly.)
What we did for optional<> is allow you to access the value in 2 ways:
optional<int> oi;
int x = oi.value(); // throws bad_optional_access int y = *oi; // undefined behaviour
Similar to vector [n] vs at(n).
I think expected<> should work the same way.
The only question, to me, is what it throws. Either it throws the Error, or it throws bad_expected_access. Or it throws bad_expected_access<Error> which derives from bad_expected_access_base, or something like that. (ie a well defined exception, but I can still get my custom Error value back from it if I want.)
IMO, expected::value()/get() must throw the container Exception (if any). expected_or_error::value()/get() should throw bad_expected_access which would contain the error condition. bad_expected_access could share the design of future_error. Best, Vicente
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor
if the expected<> has not been read?
I don't think anything in the standard throws in its destructor. (C++14
might add the ability to detect whether you are already unwinding, so that
might help here, although it is still questionable.)
I was imagining just an excepted
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read? Why would you want to that?
I was imagining just an excepted
class. I forgot about the novel throwing behaviour.
This will correspond to expected_or_error. Best, Vicente
On Wed, Apr 24, 2013 at 12:47 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read?
Why would you want to that?
I didn't say I did, but some might. And the Alexandrescu version (which was referenced as one design) works that way.
I was imagining just an excepted
class. I forgot about the novel throwing behaviour. This will correspond to expected_or_error.
I'm hoping for just one class, not multiple.
Best, Vicente
Tony
Le 24/04/13 19:49, Gottlob Frege a écrit :
On Wed, Apr 24, 2013 at 12:47 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read?
Why would you want to that?
I didn't say I did, but some might. And the Alexandrescu version (which was referenced as one design) works that way. I didn't understood it this way. I've checked the slides and I have not found nothing about the destructor. Could you point me where have you found that the destructor throws if the value were not read?
I was imagining just an excepted
class. I forgot about the novel throwing behaviour. This will correspond to expected_or_error.
I'm hoping for just one class, not multiple.
I didn't catch that you were suggesting to have
template
On Wed, Apr 24, 2013 at 5:29 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 19:49, Gottlob Frege a écrit :
On Wed, Apr 24, 2013 at 12:47 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read?
Why would you want to that?
I didn't say I did, but some might. And the Alexandrescu version (which was referenced as one design) works that way.
I didn't understood it this way. I've checked the slides and I have not found nothing about the destructor. Could you point me where have you found that the destructor throws if the value were not read?
Sorry, I must have been thinking of a different Alexandrescu class. He has/had an error class where if you didn't read the error, it threw in the destructor. I was inadvertently mixing the two concepts together.
I was imagining just an excepted
class. I forgot about the novel throwing behaviour.
This will correspond to expected_or_error.
I'm hoping for just one class, not multiple.
I didn't catch that you were suggesting to have
template
class expected; Humm, this could be done, but the has_exception function has no sense if the ExceptionalType is not exception_ptr. But a get_exceptional and accept_exceptional_visitor have sense in both cases.
Best, Vicente
I'm just thinking that having the error be an exception is too specific. I'd prefer a single class where the error might just be an error code, or might be a full exception of some kind. *If* we could give it reasonable behaviour for both cases. (Or compromise.) Otherwise we have multiple expected_* classes, which I think lowers the value of each (in this case). Maybe separate classes is best, but I suspect that a single class would have a better chance of eventual standardization. But I should probably just stop commenting, and wait and see what comes out of this. I'm having a hard time (and have a lack of time) following this, so once the class is more concrete it should be easier to discuss. Tony
On 04/25/2013 12:08 AM, Gottlob Frege wrote:
On Wed, Apr 24, 2013 at 5:29 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 19:49, Gottlob Frege a écrit :
On Wed, Apr 24, 2013 at 12:47 PM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read?
Why would you want to that?
I didn't say I did, but some might. And the Alexandrescu version (which was referenced as one design) works that way.
I didn't understood it this way. I've checked the slides and I have not found nothing about the destructor. Could you point me where have you found that the destructor throws if the value were not read?
Sorry, I must have been thinking of a different Alexandrescu class. He has/had an error class where if you didn't read the error, it threw in the destructor. I was inadvertently mixing the two concepts together.
I was imagining just an excepted
class. I forgot about the novel throwing behaviour.
This will correspond to expected_or_error.
I'm hoping for just one class, not multiple.
I didn't catch that you were suggesting to have
template
class expected; Humm, this could be done, but the has_exception function has no sense if the ExceptionalType is not exception_ptr. But a get_exceptional and accept_exceptional_visitor have sense in both cases.
Best, Vicente
I'm just thinking that having the error be an exception is too specific. I'd prefer a single class where the error might just be an error code, or might be a full exception of some kind. *If* we could give it reasonable behaviour for both cases. (Or compromise.) Otherwise we have multiple expected_* classes, which I think lowers the value of each (in this case). Maybe separate classes is best, but I suspect that a single class would have a better chance of eventual standardization.
But I should probably just stop commenting, and wait and see what comes out of this. I'm having a hard time (and have a lack of time) following this, so once the class is more concrete it should be easier to discuss.
Tony
If we want to stick to a single class, I think that the expected<T> containing a std::exception_ptr is best. Why ? Because it enables cool features with current_exception and because the standard provides exception classes even for error code. The new error_condition/error_code class can be wrapped into system_error which is an exception. That's mean that the standard provides exception classes even for error code. If we take that into account, I think expected<T> with exception inside is enough. For non-standard error code, the user can easily wrap an error inside an exception (even if the user never thrown). We could provide facilities for wrapping error code inside exception too. If you think I'm right, I'd like to focus my proposal on such an idea. Time is missing (at least for the GSoC), and I must hurry up. Thanks for the great discussions, Pierre T.
On Thu, Apr 25, 2013 at 4:05 AM, Pierre T.
If we want to stick to a single class, I think that the expected<T> containing a std::exception_ptr is best. Why ? Because it enables cool features with current_exception and because the standard provides exception classes even for error code. The new error_condition/error_code class can be wrapped into system_error which is an exception. That's mean that the standard provides exception classes even for error code. If we take that into account, I think expected<T> with exception inside is enough. For non-standard error code, the user can easily wrap an error inside an exception (even if the user never thrown). We could provide facilities for wrapping error code inside exception too.
If you think I'm right, I'd like to focus my proposal on such an idea. Time is missing (at least for the GSoC), and I must hurry up.
Thanks for the great discussions, Pierre T.
I think you should do whatever you think is best. At least get started
down that road. It always can be (and will be) tweaked later.
I would just like to keep in mind *some* way for the simple 'error code'
case to be handled (and I don't mean std::error_code, which looks too
complicated or not appropriate for custom errors). ie a simple wrapper
enum MyErrors
{
PrinterOnFire, DeveloperGoneInsane, ....
};
expected
On 04/24/2013 11:29 PM, Vicente J. Botet Escriba wrote:
Le 24/04/13 19:49, Gottlob Frege a écrit :
On Wed, Apr 24, 2013 at 12:47 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 24/04/13 18:02, Gottlob Frege a écrit :
One thing I missed in this conversation:
Are we considering the Alexandrescu behaviour of throwing in the destructor if the expected<> has not been read?
Why would you want to that?
I didn't say I did, but some might. And the Alexandrescu version (which was referenced as one design) works that way. I didn't understood it this way. I've checked the slides and I have not found nothing about the destructor. Could you point me where have you found that the destructor throws if the value were not read?
I was imagining just an excepted
class. I forgot about the novel throwing behaviour. This will correspond to expected_or_error.
I'm hoping for just one class, not multiple.
I didn't catch that you were suggesting to have
template
class expected; Humm, this could be done, but the has_exception function has no sense if the ExceptionalType is not exception_ptr. But a get_exceptional and accept_exceptional_visitor have sense in both cases.
Best, Vicente
That's sound weird to me. The fact that ExceptionalType is a std::exception_ptr enables specific behavior in many functions such as the expected::get(): if ExceptionalType is a std::exception_ptr it throws, otherwise (pick up your favorite): * it does nothing (undefined behavior); * it wrappes the ExceptionalType into an exception. Also with the default constructor, with exception it captures the current exception, otherwise I guess the expected class shouldn't have a default constructor. Or again the factory make_noexcept_expected(F&& fun); that is relevant only if ExceptionalType is an exception. I totally agree that expected would be better with only one interface. But, IMHO, we would move out the cool features and the expected class would look like a variant with specific semantic. Thanks for all the great comments, Pierre T.
Le 13/04/13 08:38, Pierre T. a écrit :
Hello,
My name is Pierre Talbot, I participated to GSoC 2011 and began the implementation of the Boost.Check library (for checking the validity of any number having a check digit — credit card number, ISBN, …). It was two years ago and the design is still evolving due to many variation points in the code. One of the function looks like :
template
boost::optional<typename check_algo::checkdigit_type> compute_checkdigit(const range &x); Using boost::optional tell us that: "A check digit should be computed if 'x' is a valid sequence". Since 'x' has many reasons to be incorrect, many errors could be raised. Based on a policy template class, it launches exception or returns with an empty optional . Then I though a lot about a better way to do it, allowing the user to get an exception or an error code. But it was quite complex for a so little part of my library… I decided that the policy "throw exception or nothing" should be enough.
Yesterday, I watched the video of Mr. Alexandrescu on Boost.Expected and I think it would be a very useful library. It could mainly be useful in system programming (where many error codes can arise from a single call), but in any code where many exception errors can be thrown (like in Boost.Check).
As you suspected, I'm interested in coding Boost.Expected during the summer as a GSoC student.
Great.
Firstly, it could be very useful to list the resources on the subject (aside the talk), I have several articles that I will talk about later.
Secondly, and hoping you'll debate, I would like to ask your opinion about several ideas and facts:
1) In the Boost project description, we can read: "adding a class expected-or-error_code". Obviously, the main design decision made by Alexandrescu is to consider that error code are exception. Do we need an abstraction of exception/error code ? Why do you think a "expected-or-error_code" class is interesting ?
During discussion on how to implement c++ concurrent queue [1] it was suggested in [2] that a value-or-status class will help to make the interface more functional. [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html [2] http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDQQFjAA&url=http%3A%2F%2Fgroups.google.com%2Fa%2Fisocpp.org%2Fgroup%2Fstd-proposals%2Fbrowse_thread%2Fthread%2F83db324ec26a0ab1%2Fb0cf6422f8d95803%3Fshow_docid%3Db0cf6422f8d95803&ei=Lz1pUYD1IJOR0QWtloDwDg&usg=AFQjCNFGiNLdGOaX9cse2vkRmTiXEUS5BA&sig2=Ho882VjpxYDrpnZow5wmxg&bvm=bv.45175338,d.d2k instead of having void pop(T&); queue_op_status try_pop(T&); T value_pop(); we could just have a value-or-status pop(); This class is very close to Expected, but instead of storing an exception, it stores the status (or error_code). It is a class that is more adapted to lower interfaces that need to check the error code and handle the error and for libraries that find expensive to throw an exception or just can-not use exceptions. I would say that this class is a must to have in the library.
2) Consider this code (from Alexandrescu slides) :
// Caller string s = readline(); auto x = parseInt(s).get(); // throw on error auto y = parseInt(s); // won’t throw if (!y.valid()) { // handle locally if (y.hasExceptionstd::invalid_argument()) { // ------------------ < The flagged line. // no digits ... } y.get(); // just "re"throw }
The flagged line has some tastes of "return to the past" flavor. Back to the C procedural language, the basic error code handling system was a lot criticized because:
* Readability of the code decrease ; * Error handling occurs in the middle of the execution flow ; * <Add your favourite reason here>.
Several links on the subjects (if you have others, I'm interested)
http://www.joelonsoftware.com/articles/Wrong.html http://www.joelonsoftware.com/items/2003/10/13.html http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx http://nedbatchelder.com/text/exceptions-vs-status.html I don't find any more the slides of Alexandrescu's presentation. I have
Well as you know this is a question of taste and taste can not be discussed. them so if you can not find them neither I can send you them privately. I 'll take a look to this links soon.
Basically, only the last one is clearly for exception. The main argument against the procedural approach is the readability. I would say that the Expected approach just differ by allowing to rethrow exception. But if you want to handle it, you must code multiple if-than-else statements.
Agreed. expected can be see as a variant at two levels. The fist one contains a value or an exception_ptr. So accept_visitor could have a sens. In addition exception_ptr is some kind of any exception where the exceptions can for a hierarchy. So any kind of hierarchical accept_visitor could be applied as well. Just note that the expected-or-error code can use a switch. No need for if-then-else.
So I considered a complementary approach working with Expected to handle multiple error cases:
string visa_number = readline(); expected<char> expected_checkdigit = compute_checkdigit<visa>(visa_number); if(expected_checkdigit.valid(visa_error_resolver)) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; }
With this code, there is only a if statement, and no more multiple error cases handles. But what is this error_resolver ?
It may be declared as :
// Somewhere in visa.hpp. A type list. typedef error_list
visa_errors; // Somewhere in the user code. error_resolver
visa_error_resolver; // in this case, expected_type is a char. // Initialize error handler on specific exception/errors. visa_error_resolver.on
(size_error_handler) .on (unknown_character_exception) ...
This approach and other forms of the hierarchical visitor pattern can be considered of course. I would not however use it with the valid function but with a specific visit function. if(expected_checkdigit.valid()) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; } else { expected_checkdigit.visit(visa_error_resolver); } In addition this visitor could be applied to any exception_ptr, so we can even provide it independently of the expected library as far as expected provide access to the exception_ptr. visit(expected_checkdigit.get_exception_ptr(), visa_error_resolver);
Now we are agree that visa_error_resolver can be reused everywhere we want to resolve an error on a visa number.
What are the handlers ? There are [Function|Functor|Lambda] (pick up your favourite) with this form :
expected<ExpectedType> size_error_handler(const size_error_exception&) expected<ExpectedType> unknown_character_exception(const unknown_character_exception&)
Now you can understand for what the type list "error_list" stands for, we can store these handlers into the error_resolver and call them without any virtual cost. I wold prefer to maintain expected<> as simple as possible and don't add anything that is not mandatory. But of course this is your talk.
Why the return type of error handler is expected<ExpectedType> ?
Consider this size_error_handler code :
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "The number you gave has a bad size." << std::endl; std::cout << "Enter it again : " << std::endl; return read_visa_checkdigit(); }
read_visa_checkdigit can call recursively valid() until it's valid. Though there are some ways to make this treatment iterative.
A basic treatment could be to print an warning message and just returns (in this case, valid returns false):
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "Warning: the VISA field is incorrect." << std::endl; return expected<ReturnType>::fromException(e); }
Results: * The error code handling is delegated to specific functions ; * The readability is still excellent ; * You can easily re-use your error handler function ; * If you don't like it, you can still throw exception on failure with "get()".
I can code a "proof of concept" if you think this is a good idea. I have started a basic implementation of expected<>. I would share it with you soon. Maybe you can start to prototype the visitor pattern applied to an exception_ptr. Do not hesitate to comment it, point out programming pitfalls, request further clarification, or anything you judge useful.
Thank you for reading it !
I see you have a lot of excellent ideas. The fist thing to do is to make a concrete proposal. Put all of what you have in mind. Make a realistic proposal, a plan and ensure that you will be able to make ready for review the library an the end of the GSoC period. I would not mentor a proposal that has to propose for review to the Boost community at the end of the summer. Maybe other mentors could appreciate your proposal even if it don't satisfy my constraints, so make the proposal you are confident with, at the end it is youself that would work on it not the mentor. Good luck, Vicente
On 04/13/2013 01:23 PM, Vicente J. Botet Escriba wrote:
Le 13/04/13 08:38, Pierre T. a écrit :
Hello,
My name is Pierre Talbot, I participated to GSoC 2011 and began the implementation of the Boost.Check library (for checking the validity of any number having a check digit — credit card number, ISBN, …). It was two years ago and the design is still evolving due to many variation points in the code. One of the function looks like :
template
boost::optional<typename check_algo::checkdigit_type> compute_checkdigit(const range &x); Using boost::optional tell us that: "A check digit should be computed if 'x' is a valid sequence". Since 'x' has many reasons to be incorrect, many errors could be raised. Based on a policy template class, it launches exception or returns with an empty optional . Then I though a lot about a better way to do it, allowing the user to get an exception or an error code. But it was quite complex for a so little part of my library… I decided that the policy "throw exception or nothing" should be enough.
Yesterday, I watched the video of Mr. Alexandrescu on Boost.Expected and I think it would be a very useful library. It could mainly be useful in system programming (where many error codes can arise from a single call), but in any code where many exception errors can be thrown (like in Boost.Check).
As you suspected, I'm interested in coding Boost.Expected during the summer as a GSoC student.
Great.
Firstly, it could be very useful to list the resources on the subject (aside the talk), I have several articles that I will talk about later.
Secondly, and hoping you'll debate, I would like to ask your opinion about several ideas and facts:
1) In the Boost project description, we can read: "adding a class expected-or-error_code". Obviously, the main design decision made by Alexandrescu is to consider that error code are exception. Do we need an abstraction of exception/error code ? Why do you think a "expected-or-error_code" class is interesting ?
During discussion on how to implement c++ concurrent queue [1] it was suggested in [2] that a value-or-status class will help to make the interface more functional.
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html [2] http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDQQFjAA&url=http%3A%2F%2Fgroups.google.com%2Fa%2Fisocpp.org%2Fgroup%2Fstd-proposals%2Fbrowse_thread%2Fthread%2F83db324ec26a0ab1%2Fb0cf6422f8d95803%3Fshow_docid%3Db0cf6422f8d95803&ei=Lz1pUYD1IJOR0QWtloDwDg&usg=AFQjCNFGiNLdGOaX9cse2vkRmTiXEUS5BA&sig2=Ho882VjpxYDrpnZow5wmxg&bvm=bv.45175338,d.d2k
instead of having
void pop(T&); queue_op_status try_pop(T&); T value_pop();
we could just have a
value-or-status pop();
This class is very close to Expected, but instead of storing an exception, it stores the status (or error_code). It is a class that is more adapted to lower interfaces that need to check the error code and handle the error and for libraries that find expensive to throw an exception or just can-not use exceptions. I would say that this class is a must to have in the library.
2) Consider this code (from Alexandrescu slides) :
// Caller string s = readline(); auto x = parseInt(s).get(); // throw on error auto y = parseInt(s); // won’t throw if (!y.valid()) { // handle locally if (y.hasExceptionstd::invalid_argument()) { // ------------------ < The flagged line. // no digits ... } y.get(); // just "re"throw }
The flagged line has some tastes of "return to the past" flavor. Back to the C procedural language, the basic error code handling system was a lot criticized because:
* Readability of the code decrease ; * Error handling occurs in the middle of the execution flow ; * <Add your favourite reason here>.
Several links on the subjects (if you have others, I'm interested)
http://www.joelonsoftware.com/articles/Wrong.html http://www.joelonsoftware.com/items/2003/10/13.html http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx http://nedbatchelder.com/text/exceptions-vs-status.html I don't find any more the slides of Alexandrescu's presentation. I have them so if you can not find them neither I can send you them
Well as you know this is a question of taste and taste can not be discussed. privately. I 'll take a look to this links soon. In the video comments, there is this link : https://skydrive.live.com/?cid=f1b8ff18a2aec5c5&id=F1B8FF18A2AEC5C5!1158&authkey=!APo6bfP5sJ8EmH4
Basically, only the last one is clearly for exception. The main argument against the procedural approach is the readability. I would say that the Expected approach just differ by allowing to rethrow exception. But if you want to handle it, you must code multiple if-than-else statements.
Agreed. expected can be see as a variant at two levels. The fist one contains a value or an exception_ptr. So accept_visitor could have a sens. In addition exception_ptr is some kind of any exception where the exceptions can for a hierarchy. So any kind of hierarchical accept_visitor could be applied as well.
Just note that the expected-or-error code can use a switch. No need for if-then-else. switch and if-then-else are quite similar, aren't they?
So I considered a complementary approach working with Expected to handle multiple error cases:
string visa_number = readline(); expected<char> expected_checkdigit = compute_checkdigit<visa>(visa_number); if(expected_checkdigit.valid(visa_error_resolver)) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; }
With this code, there is only a if statement, and no more multiple error cases handles. But what is this error_resolver ?
It may be declared as :
// Somewhere in visa.hpp. A type list. typedef error_list
visa_errors; // Somewhere in the user code. error_resolver
visa_error_resolver; // in this case, expected_type is a char. // Initialize error handler on specific exception/errors. visa_error_resolver.on
(size_error_handler) .on (unknown_character_exception) ... This approach and other forms of the hierarchical visitor pattern can be considered of course. I would not however use it with the valid function but with a specific visit function.
if(expected_checkdigit.valid()) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; } else { expected_checkdigit.visit(visa_error_resolver); }
In addition this visitor could be applied to any exception_ptr, so we can even provide it independently of the expected library as far as expected provide access to the exception_ptr.
visit(expected_checkdigit.get_exception_ptr(), visa_error_resolver); This is two more lines for a very common case. We should rename valid(error_resolver&) for validate ? Or feel free to propose any suggestions.
Now we are agree that visa_error_resolver can be reused everywhere we want to resolve an error on a visa number.
What are the handlers ? There are [Function|Functor|Lambda] (pick up your favourite) with this form :
expected<ExpectedType> size_error_handler(const size_error_exception&) expected<ExpectedType> unknown_character_exception(const unknown_character_exception&)
Now you can understand for what the type list "error_list" stands for, we can store these handlers into the error_resolver and call them without any virtual cost. I wold prefer to maintain expected<> as simple as possible and don't add anything that is not mandatory. But of course this is your talk. I'm not sure that my explanation is clear. In fact these two functions are not related to expected<>. They are the visitor.
Why the return type of error handler is expected<ExpectedType> ?
Consider this size_error_handler code :
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "The number you gave has a bad size." << std::endl; std::cout << "Enter it again : " << std::endl; return read_visa_checkdigit(); }
read_visa_checkdigit can call recursively valid() until it's valid. Though there are some ways to make this treatment iterative.
A basic treatment could be to print an warning message and just returns (in this case, valid returns false):
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "Warning: the VISA field is incorrect." << std::endl; return expected<ReturnType>::fromException(e); }
Results: * The error code handling is delegated to specific functions ; * The readability is still excellent ; * You can easily re-use your error handler function ; * If you don't like it, you can still throw exception on failure with "get()".
I can code a "proof of concept" if you think this is a good idea. I have started a basic implementation of expected<>. I would share it with you soon. Maybe you can start to prototype the visitor pattern applied to an exception_ptr. I have the Alexandrescu class, copied from the slides. But I would be glad to see yours too. Do not hesitate to comment it, point out programming pitfalls, request further clarification, or anything you judge useful.
Thank you for reading it !
I see you have a lot of excellent ideas. The fist thing to do is to make a concrete proposal. Put all of what you have in mind. Make a realistic proposal, a plan and ensure that you will be able to make ready for review the library an the end of the GSoC period. I would not mentor a proposal that has to propose for review to the Boost community at the end of the summer.
Maybe other mentors could appreciate your proposal even if it don't satisfy my constraints, so make the proposal you are confident with, at the end it is youself that would work on it not the mentor.
Good luck, Vicente
Before going further with an implementation try, I would like to have
your opinion on this simple idea:
I'm not sure that expected should encapsulate an exception. Moreover the
std::exception_pointer introduces virtuality that could be quite
intrusive for the low-level interface.
I propose that expected use a type list of error such as :
typedef ErrorList
Le 13/04/13 16:24, Pierre T. a écrit :
On 04/13/2013 01:23 PM, Vicente J. Botet Escriba wrote:
Le 13/04/13 08:38, Pierre T. a écrit :
Hello,
My name is Pierre Talbot, I participated to GSoC 2011 and began the implementation of the Boost.Check library (for checking the validity of any number having a check digit — credit card number, ISBN, …). It was two years ago and the design is still evolving due to many variation points in the code. One of the function looks like :
template
boost::optional<typename check_algo::checkdigit_type> compute_checkdigit(const range &x); Using boost::optional tell us that: "A check digit should be computed if 'x' is a valid sequence". Since 'x' has many reasons to be incorrect, many errors could be raised. Based on a policy template class, it launches exception or returns with an empty optional . Then I though a lot about a better way to do it, allowing the user to get an exception or an error code. But it was quite complex for a so little part of my library… I decided that the policy "throw exception or nothing" should be enough.
Yesterday, I watched the video of Mr. Alexandrescu on Boost.Expected and I think it would be a very useful library. It could mainly be useful in system programming (where many error codes can arise from a single call), but in any code where many exception errors can be thrown (like in Boost.Check).
As you suspected, I'm interested in coding Boost.Expected during the summer as a GSoC student.
Great.
Firstly, it could be very useful to list the resources on the subject (aside the talk), I have several articles that I will talk about later.
Secondly, and hoping you'll debate, I would like to ask your opinion about several ideas and facts:
1) In the Boost project description, we can read: "adding a class expected-or-error_code". Obviously, the main design decision made by Alexandrescu is to consider that error code are exception. Do we need an abstraction of exception/error code ? Why do you think a "expected-or-error_code" class is interesting ?
During discussion on how to implement c++ concurrent queue [1] it was suggested in [2] that a value-or-status class will help to make the interface more functional.
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html [2] http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDQQFjAA&url=http%3A%2F%2Fgroups.google.com%2Fa%2Fisocpp.org%2Fgroup%2Fstd-proposals%2Fbrowse_thread%2Fthread%2F83db324ec26a0ab1%2Fb0cf6422f8d95803%3Fshow_docid%3Db0cf6422f8d95803&ei=Lz1pUYD1IJOR0QWtloDwDg&usg=AFQjCNFGiNLdGOaX9cse2vkRmTiXEUS5BA&sig2=Ho882VjpxYDrpnZow5wmxg&bvm=bv.45175338,d.d2k
instead of having
void pop(T&); queue_op_status try_pop(T&); T value_pop();
we could just have a
value-or-status pop();
This class is very close to Expected, but instead of storing an exception, it stores the status (or error_code). It is a class that is more adapted to lower interfaces that need to check the error code and handle the error and for libraries that find expensive to throw an exception or just can-not use exceptions. I would say that this class is a must to have in the library.
2) Consider this code (from Alexandrescu slides) :
// Caller string s = readline(); auto x = parseInt(s).get(); // throw on error auto y = parseInt(s); // won’t throw if (!y.valid()) { // handle locally if (y.hasExceptionstd::invalid_argument()) { // ------------------ < The flagged line. // no digits ... } y.get(); // just "re"throw }
The flagged line has some tastes of "return to the past" flavor. Back to the C procedural language, the basic error code handling system was a lot criticized because:
* Readability of the code decrease ; * Error handling occurs in the middle of the execution flow ; * <Add your favourite reason here>.
Several links on the subjects (if you have others, I'm interested)
http://www.joelonsoftware.com/articles/Wrong.html http://www.joelonsoftware.com/items/2003/10/13.html http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx http://nedbatchelder.com/text/exceptions-vs-status.html I don't find any more the slides of Alexandrescu's presentation. I have them so if you can not find them neither I can send you them
Well as you know this is a question of taste and taste can not be discussed. privately. I 'll take a look to this links soon. In the video comments, there is this link : https://skydrive.live.com/?cid=f1b8ff18a2aec5c5&id=F1B8FF18A2AEC5C5!1158&authkey=!APo6bfP5sJ8EmH4
Basically, only the last one is clearly for exception. The main argument against the procedural approach is the readability. I would say that the Expected approach just differ by allowing to rethrow exception. But if you want to handle it, you must code multiple if-than-else statements.
Agreed. expected can be see as a variant at two levels. The fist one contains a value or an exception_ptr. So accept_visitor could have a sens. In addition exception_ptr is some kind of any exception where the exceptions can for a hierarchy. So any kind of hierarchical accept_visitor could be applied as well.
Just note that the expected-or-error code can use a switch. No need for if-then-else. switch and if-then-else are quite similar, aren't they?
So I considered a complementary approach working with Expected to handle multiple error cases:
string visa_number = readline(); expected<char> expected_checkdigit = compute_checkdigit<visa>(visa_number); if(expected_checkdigit.valid(visa_error_resolver)) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; }
With this code, there is only a if statement, and no more multiple error cases handles. But what is this error_resolver ?
It may be declared as :
// Somewhere in visa.hpp. A type list. typedef error_list
visa_errors; // Somewhere in the user code. error_resolver
visa_error_resolver; // in this case, expected_type is a char. // Initialize error handler on specific exception/errors. visa_error_resolver.on
(size_error_handler) .on (unknown_character_exception) ... This approach and other forms of the hierarchical visitor pattern can be considered of course. I would not however use it with the valid function but with a specific visit function.
if(expected_checkdigit.valid()) { visa_number += expected_checkdigit.get(); std::cout << visa_number << std::endl; } else { expected_checkdigit.visit(visa_error_resolver); }
In addition this visitor could be applied to any exception_ptr, so we can even provide it independently of the expected library as far as expected provide access to the exception_ptr.
visit(expected_checkdigit.get_exception_ptr(), visa_error_resolver); This is two more lines for a very common case. We should rename valid(error_resolver&) for validate ? Or feel free to propose any suggestions.
Now we are agree that visa_error_resolver can be reused everywhere we want to resolve an error on a visa number.
What are the handlers ? There are [Function|Functor|Lambda] (pick up your favourite) with this form :
expected<ExpectedType> size_error_handler(const size_error_exception&) expected<ExpectedType> unknown_character_exception(const unknown_character_exception&)
Now you can understand for what the type list "error_list" stands for, we can store these handlers into the error_resolver and call them without any virtual cost. I wold prefer to maintain expected<> as simple as possible and don't add anything that is not mandatory. But of course this is your talk. I'm not sure that my explanation is clear. In fact these two functions are not related to expected<>. They are the visitor.
Why the return type of error handler is expected<ExpectedType> ?
Consider this size_error_handler code :
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "The number you gave has a bad size." << std::endl; std::cout << "Enter it again : " << std::endl; return read_visa_checkdigit(); }
read_visa_checkdigit can call recursively valid() until it's valid. Though there are some ways to make this treatment iterative.
A basic treatment could be to print an warning message and just returns (in this case, valid returns false):
expected<ReturnType> size_error_handler(const size_error_exception& e) { std::cout << "Warning: the VISA field is incorrect." << std::endl; return expected<ReturnType>::fromException(e); }
Results: * The error code handling is delegated to specific functions ; * The readability is still excellent ; * You can easily re-use your error handler function ; * If you don't like it, you can still throw exception on failure with "get()".
I can code a "proof of concept" if you think this is a good idea. I have started a basic implementation of expected<>. I would share it with you soon. Maybe you can start to prototype the visitor pattern applied to an exception_ptr. I have the Alexandrescu class, copied from the slides. But I would be glad to see yours too. Do not hesitate to comment it, point out programming pitfalls, request further clarification, or anything you judge useful.
Thank you for reading it !
I see you have a lot of excellent ideas. The fist thing to do is to make a concrete proposal. Put all of what you have in mind. Make a realistic proposal, a plan and ensure that you will be able to make ready for review the library an the end of the GSoC period. I would not mentor a proposal that has to propose for review to the Boost community at the end of the summer.
Maybe other mentors could appreciate your proposal even if it don't satisfy my constraints, so make the proposal you are confident with, at the end it is youself that would work on it not the mentor.
Good luck, Vicente
Before going further with an implementation try, I would like to have your opinion on this simple idea:
I'm not sure that expected should encapsulate an exception. Moreover the std::exception_pointer introduces virtuality that could be quite intrusive for the low-level interface. No more than throwing exceptions. This is why we need expected-or-error-code. I propose that expected use a type list of error such as :
typedef ErrorList
MyErrorList; typedef expected ExpectedReturnType; ExpectedReturnType value = …;
* The visitor could have the advantage to be static. I have not taken the time to analyze this static approach. What is the advantage of making the exceptions static? Humm, this is quite close to declare the exceptions a function can throw which we know is no so good. What would be the size of this expected type? * The user can put error class, exception error class. We could specialize it for error code too I guess. Humm, this start to be to close to boost::variant. What would be the real difference with Boost.Variant?
I have further facilities ideas that I will show you later if you think that could be a good compromise.
My intention was to have a expected<> class that is quite close to the one of Alexandrescu to which we can add things that improve them but no things that make it worst. Using more space than Expected make it worst for me. Remember that in addition Expected should be movable if T is movable. Next implement expected-or-error_code. This doesn't means that you can not explore alternative design if you have enough time, compare them, and provide some performances figures that would help the user to make its choice. Yes this will be really great. Let me know if this in line respect your expectations. Best, Vicente
Hello, I wrote a proposal for the Boost.Expected project. You can find a pdf version here: http://hyc.io/boost/boost-expected-proposal.pdf It's about the Boost.Expected project, I'll add my own informations by the end of the week. Finally, I propose a single class design, and facilities for custom error code. It's based on the Alexendrescu idea upgraded by Vicente J. Botet Escriba and myself. I also took into account the Boost.Optional class. If needed for this proposal, I can add documentation per method (such as in official proposal), but I'm not sure it's useful without a frozen interface. Please do not hesitate to comment it and request further clarification, Many thanks to all for the ideas and the discussions. Pierre T.
Le 26/04/13 14:22, Pierre T. a écrit :
Hello,
I wrote a proposal for the Boost.Expected project. You can find a pdf version here:
http://hyc.io/boost/boost-expected-proposal.pdf
It's about the Boost.Expected project, I'll add my own informations by the end of the week.
Finally, I propose a single class design, and facilities for custom error code. It's based on the Alexendrescu idea upgraded by Vicente J. Botet Escriba and myself. I also took into account the Boost.Optional class. If needed for this proposal, I can add documentation per method (such as in official proposal), but I'm not sure it's useful without a frozen interface.
Please do not hesitate to comment it and request further clarification,
Hi,
first of all, thanks for writing this proposal.
I have some concerns
* Single class:
I'm all for a single class; but having an ExceptionalType template
parameter which defaults to exception_ptr.
template
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
Le 26/04/13 14:22, Pierre T. a écrit :
Hello,
I wrote a proposal for the Boost.Expected project. You can find a pdf version here:
http://hyc.io/boost/boost-expected-proposal.pdf
It's about the Boost.Expected project, I'll add my own informations by the end of the week.
Finally, I propose a single class design, and facilities for custom error code. It's based on the Alexendrescu idea upgraded by Vicente J. Botet Escriba and myself. I also took into account the Boost.Optional class. If needed for this proposal, I can add documentation per method (such as in official proposal), but I'm not sure it's useful without a frozen interface.
Please do not hesitate to comment it and request further clarification,
Hi,
first of all, thanks for writing this proposal.
I have some concerns
* Single class: I'm all for a single class; but having an ExceptionalType template parameter which defaults to exception_ptr.
template
class expected; We could define the traits that make the difference between having an exception_ptr and another error
template <typename ExceptionalType> struct exceptional_traits { typedef ExceptionalType exceptional_type; template <class E> static exceptional_type make_exceptional(E const& except) { return exceptional_type(except) } static exceptional_type current_exceptional() { return exceptional_type() } static void rethrow(exceptional_type except) { boost::throw_exception(bad_expected_access
(except)); } }; template <> struct exceptional_traits { typedef ExceptionalType exceptional_type; template <class E> static exceptional_type make_exceptional(E const& except) { return boost::make_exception_ptr(except); } static exceptional_type current_exceptional() { return boost::current_exception() } static void rethrow(exceptional_type except); { boost::rethrow_exception(except); } template <class E> static bool has_exception(bool valid, exceptional_type except) const BOOST_NOEXCEPT { try { if (!valid) rethrow(except); } catch (const E& ex) { return true; } catch (...) { } return false; } }; }
With these traits we are able to define the functions that have a specific behavior as e.g.
typedef detail::exceptional_traits
traits; expected() BOOST_NOEXCEPT : except_(traits::current_exceptional()) , has_value_(false) {} const T& get() const { if (!valid()) traits::rethrow(except_); return value_; } template <class E> bool has_exception() const BOOST_NOEXCEPT { return traits::has_exception(except_); }
I like this proposition but at first, it seems a bit "overkill". I would like to have more opinions about it. Through it seems to be less compatible with the "visitor" idea. The visitor resolves on types and most of the error code have a same type. So it would visit only one type.
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like: expected<int> e; if(…) else(…) return e; Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected.
* then/otherwise issues
Humm, I don't agree here with the proposed design (even if I made the then suggestion). What returns the then function if the instance has a value? I declared it as
template <typename F> expected
::type> then(F&& fuct) Let me name typedef typename boost::result_of
so the result would return the expected<RT>(fuct(value_)). Chaining this temporary with an otherwise call will work with the new temporary, and not with the original expected. I don't think this was what was expected ;-)
E.g.
string f(int); int f(string);
expected<int> e= 1; e.then(f).otherwise(g);
Here g will be called with expected<string>(fuct(value_)).except_. Hrrr
expected<int> e= make_exceptional_expect(X); e.then(f).otherwise(g);
Here g will be called with the exception_ptr stored in e. Hrrr
That is g don't know if it is called with an exception stored on e or on the temporary resulting for the call to f.
But the design error is not on the otherwise function but on the then function.
Resuming, I'm not more for the 'then' function.
I'm totally agree with you. But I think that I misnamed the "otherwise" method. I think the "then" method is really useful, it's like an automaton. With e.then().then().then(), the treatment is stopped anytime when an error occurs in a then method. Also, I think that the function taken by then should return void or an expected. In fact the otherwise method is the error visitor. A common usage would be to chain it in the end: e.then(...).then(...).then(...).visit_error(error_visitor); visit_error is called if any "then" return an error. I found it wonderfully useful.
Using a visitor would as you proposed initially would be better.
template <class V> void accept_visitor(V& visitor) const BOOST_NOEXCEPT { if (valid()) visitor.visit(value_); else visitor.visit(expectional, except_); }
I'm not sure that we should use the visitor pattern for the value and the error. Initially, I though at the visitor pattern because error would be exception-based, so with some types to visit. And also to provide a way to visit exception without throwing them with the get() method.
HTH, Vicente
As usual, these discussions help a lot, but this time, I'm not sure if our idea are still good ideas, that's why more opinions would help. Thanks, Pierre T.
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
Le 26/04/13 14:22, Pierre T. a écrit :
Hello,
I wrote a proposal for the Boost.Expected project. You can find a pdf version here:
http://hyc.io/boost/boost-expected-proposal.pdf
It's about the Boost.Expected project, I'll add my own informations by the end of the week.
Finally, I propose a single class design, and facilities for custom error code. It's based on the Alexendrescu idea upgraded by Vicente J. Botet Escriba and myself. I also took into account the Boost.Optional class. If needed for this proposal, I can add documentation per method (such as in official proposal), but I'm not sure it's useful without a frozen interface.
Please do not hesitate to comment it and request further clarification,
Hi,
first of all, thanks for writing this proposal.
I have some concerns
* Single class: I'm all for a single class; but having an ExceptionalType template parameter which defaults to exception_ptr.
template
class expected; We could define the traits that make the difference between having an exception_ptr and another error
With these traits we are able to define the functions that have a specific behavior as e.g.
I like this proposition but at first, it seems a bit "overkill". I would like to have more opinions about it. Through it seems to be less compatible with the "visitor" idea. The visitor resolves on types and most of the error code have a same type. So it would visit only one type. Right. But this independent on whether you use a wrapper exception or not, isn't it?
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state
Le 27/04/13 09:39, Pierre T. a écrit : that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility?
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected.
I let you try to define move move semantics for expected and you will see why this is related.
* then/otherwise issues
Humm, I don't agree here with the proposed design (even if I made the then suggestion). What returns the then function if the instance has a value? I declared it as
template <typename F> expected
::type> then(F&& fuct) Let me name typedef typename boost::result_of
so the result would return the expected<RT>(fuct(value_)). Chaining this temporary with an otherwise call will work with the new temporary, and not with the original expected. I don't think this was what was expected ;-)
E.g.
string f(int); int f(string);
expected<int> e= 1; e.then(f).otherwise(g);
Here g will be called with expected<string>(fuct(value_)).except_. Hrrr
expected<int> e= make_exceptional_expect(X); e.then(f).otherwise(g);
Here g will be called with the exception_ptr stored in e. Hrrr
That is g don't know if it is called with an exception stored on e or on the temporary resulting for the call to f.
But the design error is not on the otherwise function but on the then function.
Resuming, I'm not more for the 'then' function.
I'm totally agree with you. But I think that I misnamed the "otherwise" method. I think the "then" method is really useful, it's like an automaton. With e.then().then().then(), the treatment is stopped anytime when an error occurs in a then method.
How would this be stopped? throwing and exception?
Also, I think that the function taken by then should return void And which value would you pass to the second then call? or an expected.
Maybe. But if we don't know how it is stopped chaining them has no sens. When the call to the function is asynchronous it is easy to stop it but synchronously it implies an exception which is against the goal of expected.
In fact the otherwise method is the error visitor. A common usage would be to chain it in the end:
e.then(...).then(...).then(...).visit_error(error_visitor);
visit_error is called if any "then" return an error. I found it wonderfully useful. This could be possible; It would need that then() returns an expression template storing all the functions on the chain and only the call to the visit_error would evaluate the chain. I don't think it is worth proving this lazy evaluation.
Using a visitor would as you proposed initially would be better.
template <class V> void accept_visitor(V& visitor) const BOOST_NOEXCEPT { if (valid()) visitor.visit(value_); else visitor.visit(expectional, except_); }
I'm not sure that we should use the visitor pattern for the value and the error. Initially, I though at the visitor pattern because error would be exception-based, so with some types to visit. And also to provide a way to visit exception without throwing them with the get() method. Well I let you think a little bit more about. The visitor is your idea. From my side I don't need it for the case where the Error is not an exception_ptr.
As usual, these discussions help a lot, but this time, I'm not sure if our idea are still good ideas, that's why more opinions would help.
Yes, it always helps to know what others think about. Very often people has no time to, or would not take the time until you present a concrete proposal and implementation so they can play with. If you send your application, I'm sure that other mentors would comment on the subject you could request to them. Best, Vicente
On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote:
Le 27/04/13 09:39, Pierre T. a écrit :
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
Le 26/04/13 14:22, Pierre T. a écrit :
Hello,
I wrote a proposal for the Boost.Expected project. You can find a pdf version here:
http://hyc.io/boost/boost-expected-proposal.pdf
It's about the Boost.Expected project, I'll add my own informations by the end of the week.
Finally, I propose a single class design, and facilities for custom error code. It's based on the Alexendrescu idea upgraded by Vicente J. Botet Escriba and myself. I also took into account the Boost.Optional class. If needed for this proposal, I can add documentation per method (such as in official proposal), but I'm not sure it's useful without a frozen interface.
Please do not hesitate to comment it and request further clarification,
Hi,
first of all, thanks for writing this proposal.
I have some concerns
* Single class: I'm all for a single class; but having an ExceptionalType template parameter which defaults to exception_ptr.
template
class expected; We could define the traits that make the difference between having an exception_ptr and another error
With these traits we are able to define the functions that have a specific behavior as e.g.
I like this proposition but at first, it seems a bit "overkill". I would like to have more opinions about it. Through it seems to be less compatible with the "visitor" idea. The visitor resolves on types and most of the error code have a same type. So it would visit only one type. Right. But this independent on whether you use a wrapper exception or not, isn't it? Yes, it gives a good point to the traits.
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility? By testing == nullexcept (operator== not in the proposal, sorry), however you are right, expected must contains an exception or a value. On the other hand, it's nice to provide a default constructor, so an idea could be to add a method "unitialized_error()" in the trait class.
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected. I let you try to define move move semantics for expected and you will see why this is related.
* then/otherwise issues
Humm, I don't agree here with the proposed design (even if I made the then suggestion). What returns the then function if the instance has a value? I declared it as
template <typename F> expected
::type> then(F&& fuct) Let me name typedef typename boost::result_of
so the result would return the expected<RT>(fuct(value_)). Chaining this temporary with an otherwise call will work with the new temporary, and not with the original expected. I don't think this was what was expected ;-)
E.g.
string f(int); int f(string);
expected<int> e= 1; e.then(f).otherwise(g);
Here g will be called with expected<string>(fuct(value_)).except_. Hrrr
expected<int> e= make_exceptional_expect(X); e.then(f).otherwise(g);
Here g will be called with the exception_ptr stored in e. Hrrr
That is g don't know if it is called with an exception stored on e or on the temporary resulting for the call to f.
But the design error is not on the otherwise function but on the then function.
Resuming, I'm not more for the 'then' function.
I'm totally agree with you. But I think that I misnamed the "otherwise" method. I think the "then" method is really useful, it's like an automaton. With e.then().then().then(), the treatment is stopped anytime when an error occurs in a then method. How would this be stopped? throwing and exception? It's not stopped but the "then" method launch the function only if expected contains a value. Also, I think that the function taken by then should return void And which value would you pass to the second then call? The same. or an expected.
In fact the otherwise method is the error visitor. A common usage would be to chain it in the end:
e.then(...).then(...).then(...).visit_error(error_visitor);
visit_error is called if any "then" return an error. I found it wonderfully useful. This could be possible; It would need that then() returns an expression template storing all the functions on the chain and only
Maybe. But if we don't know how it is stopped chaining them has no sens. When the call to the function is asynchronous it is easy to stop it but synchronously it implies an exception which is against the goal of expected. the call to the visit_error would evaluate the chain. I don't think it is worth proving this lazy evaluation. To complete what I've said, the visit_error() would launch the visitor only if the expected contains an error. No lazy evaluation is needed.
Using a visitor would as you proposed initially would be better.
template <class V> void accept_visitor(V& visitor) const BOOST_NOEXCEPT { if (valid()) visitor.visit(value_); else visitor.visit(expectional, except_); }
I'm not sure that we should use the visitor pattern for the value and the error. Initially, I though at the visitor pattern because error would be exception-based, so with some types to visit. And also to provide a way to visit exception without throwing them with the get() method.
Well I let you think a little bit more about. The visitor is your idea. From my side I don't need it for the case where the Error is not an exception_ptr.
As usual, these discussions help a lot, but this time, I'm not sure if our idea are still good ideas, that's why more opinions would help.
Yes, it always helps to know what others think about. Very often people has no time to, or would not take the time until you present a concrete proposal and implementation so they can play with. If you send your application, I'm sure that other mentors would comment on the subject you could request to them.
I'll try to send it before tomorrow. I will update it with the trait classes and the others comments you made. I just have a question about the proposal, should I use the Boost macro for noexcept,… or is it better (for a proposal) to write it with the standard tools ?
Best, Vicente
Thanks again for these comments, Pierre T.
On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote:
Le 27/04/13 09:39, Pierre T. a écrit :
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
Le 26/04/13 14:22, Pierre T. a écrit : I like this proposition but at first, it seems a bit "overkill". I would like to have more opinions about it. Through it seems to be less compatible with the "visitor" idea. The visitor resolves on types and most of the error code have a same type. So it would visit only one type. Right. But this independent on whether you use a wrapper exception or not, isn't it? Yes, it gives a good point to the traits.
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility? By testing == nullexcept (operator== not in the proposal, sorry), however you are right, expected must contains an exception or a value. On the other hand, it's nice to provide a default constructor, so an idea could be to add a method "unitialized_error()" in the trait class. Why do you need a default constructor.
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected. I let you try to define move move semantics for expected and you will see why this is related. After thinking more on this the moved object could present its exception_ptr if it has one, so move semantics doesn't force to have an uninitialized expected<>
* then/otherwise issues
But the design error is not on the otherwise function but on the then function.
Resuming, I'm not more for the 'then' function.
I'm totally agree with you. But I think that I misnamed the "otherwise" method. I think the "then" method is really useful, it's like an automaton. With e.then().then().then(), the treatment is stopped anytime when an error occurs in a then method. How would this be stopped? throwing and exception? It's not stopped but the "then" method launch the function only if expected contains a value. And what return if it not contains a value? Also, I think that the function taken by then should return void And which value would you pass to the second then call? The same. Sorry I don't follow. What The do you mean by the same? or an expected.
In fact the otherwise method is the error visitor. A common usage would be to chain it in the end:
e.then(...).then(...).then(...).visit_error(error_visitor);
visit_error is called if any "then" return an error. I found it wonderfully useful. This could be possible; It would need that then() returns an expression template storing all the functions on the chain and only
Maybe. But if we don't know how it is stopped chaining them has no sens. When the call to the function is asynchronous it is easy to stop it but synchronously it implies an exception which is against the goal of expected. the call to the visit_error would evaluate the chain. I don't think it is worth proving this lazy evaluation. To complete what I've said, the visit_error() would launch the visitor only if the expected contains an error. No lazy evaluation is needed. Ah I think I see now what was the initial intention. I suspect that you mean that as the result of e.then(f) would transport the exception stored on e if e is not valid, then the exception would be relayed until
Le 28/04/13 16:22, Pierre T. a écrit :
there is a call to visit_error and no call to any function will be done.
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try {
f3(f2(f1(f0())));
} catch(...) {
error_visitor();
}
It would be great if we could have the equivalent for
try {
h(f(), g());
} catch(...) {
error_visitor();
}
when_all(f(), g()).then(h).visit_error(error_visitor);
when_all could return a expected
I'll try to send it before tomorrow. I will update it with the trait classes and the others comments you made. I just have a question about the proposal, should I use the Boost macro for noexcept,… or is it better (for a proposal) to write it with the standard tools ? I use to document using c++11 without any reference to the emulations.
Best, Vicente
On 04/28/2013 05:20 PM, Vicente J. Botet Escriba wrote:
Le 28/04/13 16:22, Pierre T. a écrit :
Le 27/04/13 09:39, Pierre T. a écrit :
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
Le 26/04/13 14:22, Pierre T. a écrit : I like this proposition but at first, it seems a bit "overkill". I would like to have more opinions about it. Through it seems to be less compatible with the "visitor" idea. The visitor resolves on types and most of the error code have a same type. So it would visit only one type. Right. But this independent on whether you use a wrapper exception or not, isn't it? Yes, it gives a good point to the traits.
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility? By testing == nullexcept (operator== not in the proposal, sorry), however you are right, expected must contains an exception or a value. On the other hand, it's nice to provide a default constructor, so an idea could be to add a method "unitialized_error()" in the
On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote: trait class. Why do you need a default constructor. Because it can be useful for the following situation:
expected<T> func(bool b) { expected<T> e; if(b) { e = f(); // use e } else { e = g(); // use e } return e; } Some programmers prefer to have only one return statement instead of having: expected<T> func(bool b) { if(b) { expected<T> e = f(); // use e return e; } else { expected<T> e = g(); // use e return e; } }
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected.
I let you try to define move move semantics for expected and you will see why this is related. After thinking more on this the moved object could present its exception_ptr if it has one, so move semantics doesn't force to have an uninitialized expected<> Not sure to get it,
expected(expected&& e) // nothing in the initializer list because we don't know if we must move T or Error. { if(has_value) // move value else // move error } In case T or Error haven't a default constructor, the previous code can't work, right ? Could we add a dummy field in the union such as: union{ T value, Error error, bool internal_uninitialized}; But I'm not sure it's what you meant.
* then/otherwise issues
But the design error is not on the otherwise function but on the then function.
Resuming, I'm not more for the 'then' function.
I'm totally agree with you. But I think that I misnamed the "otherwise" method. I think the "then" method is really useful, it's like an automaton. With e.then().then().then(), the treatment is stopped anytime when an error occurs in a then method.
How would this be stopped? throwing and exception? It's not stopped but the "then" method launch the function only if expected contains a value. And what return if it not contains a value?
Also, I think that the function taken by then should return void And which value would you pass to the second then call? The same. Sorry I don't follow. What The do you mean by the same? or an expected.
In fact the otherwise method is the error visitor. A common usage would be to chain it in the end:
e.then(...).then(...).then(...).visit_error(error_visitor);
visit_error is called if any "then" return an error. I found it wonderfully useful. This could be possible; It would need that then() returns an expression template storing all the functions on the chain and only
Maybe. But if we don't know how it is stopped chaining them has no sens. When the call to the function is asynchronous it is easy to stop it but synchronously it implies an exception which is against the goal of expected. the call to the visit_error would evaluate the chain. I don't think it is worth proving this lazy evaluation. To complete what I've said, the visit_error() would launch the visitor only if the expected contains an error. No lazy evaluation is needed. Ah I think I see now what was the initial intention. I suspect that you mean that as the result of e.then(f) would transport the exception stored on e if e is not valid, then the exception would be relayed until there is a call to visit_error and no call to any function will be done. Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); }
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor);
when_all could return a expected
> or something more specific so that then would extract the members of the tuple to call h with two parameters. This start to look more and more like the proposal for futures (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf)
Sorry for the poor explanations about it, but you guessed correctly. I read the futures proposal and the ideas in there are really interesting. However because expected is not related to the time, I think we could just do the following: e.then(f, g).then(h).inspect(error_inspector) where "then" takes an unlimited number of functions. In this case it would return a tuple-wrapper class specific to the expected class (in case users would like to store tuple inside expected). About the "inspect" method, I try to find another name instead of visit_error because it makes me think to the pattern visitor which is too specific to hierarchy classes. I found that inspect was nice because it's like in a factory where the chief "inspects" that everything has been alright.
I'll try to send it before tomorrow. I will update it with the trait classes and the others comments you made. I just have a question about the proposal, should I use the Boost macro for noexcept,… or is it better (for a proposal) to write it with the standard tools ? I use to document using c++11 without any reference to the emulations.
Best, Vicente
Thanks, Pierre T.
Le 28/04/13 18:27, Pierre T. a écrit :
On 04/28/2013 05:20 PM, Vicente J. Botet Escriba wrote:
Le 28/04/13 16:22, Pierre T. a écrit :
On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote:
Le 27/04/13 09:39, Pierre T. a écrit :
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
* Default Constructor or constructor from nullexpect What is the advantage of having a expected instance that doesn't have neither a value nor an exception? How would the user manages with this possibility? Are you looking to make expect movable?
Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility? By testing == nullexcept (operator== not in the proposal, sorry), however you are right, expected must contains an exception or a value. On the other hand, it's nice to provide a default constructor, so an idea could be to add a method "unitialized_error()" in the trait class. Why do you need a default constructor. Because it can be useful for the following situation:
expected<T> func(bool b) { expected<T> e; if(b) { e = f(); // use e } else { e = g(); // use e } return e; }
Some programmers prefer to have only one return statement instead of having:
expected<T> func(bool b) { if(b) { expected<T> e = f(); // use e return e; } else { expected<T> e = g(); // use e return e; } }
Humm, I don't know if this is enough.
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected.
I let you try to define move move semantics for expected and you will see why this is related. After thinking more on this the moved object could present its exception_ptr if it has one, so move semantics doesn't force to have an uninitialized expected<> Not sure to get it,
expected(expected&& e) // nothing in the initializer list because we don't know if we must move T or Error. { if(has_value) // move value else // move error }
In case T or Error haven't a default constructor, the previous code can't work, right ? You would need to move construct using placement new
new (&value_) T(forward<T>(val)) ; BTW, exception_ptr move is equivalent to a copy, isn't it?
Could we add a dummy field in the union such as:
union{ T value, Error error, bool internal_uninitialized}; I don't think this is a good ideea.
But I'm not sure it's what you meant.
*Ah I think I see now what was the initial intention. I suspect that you mean that as the result of e.then(f) would transport the exception stored on e if e is not valid, then the exception would be relayed until there is a call to visit_error and no call to any function will be done.
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); }
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor);
when_all could return a expected
> or something more specific so that then would extract the members of the tuple to call h with two parameters. This start to look more and more like the proposal for futures (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf)
Sorry for the poor explanations about it, but you guessed correctly. I read the futures proposal and the ideas in there are really interesting. However because expected is not related to the time, I think we could just do the following:
e.then(f, g).then(h).inspect(error_inspector)
where "then" takes an unlimited number of functions. In this case it would return a tuple-wrapper class specific to the expected class (in case users would like to store tuple inside expected). Humm, in the example I gave above f an g are not continuations but expected<> producers. Anyway, the variadic version of then could have its uses. I like it, but it is orthogonal to the when_all feature.
What do you think about letting the continuation returning an expected<>? It has the advantage to allowing the continuation to transport exceptions also without throwing.
About the "inspect" method, I try to find another name instead of visit_error because it makes me think to the pattern visitor which is too specific to hierarchy classes. I found that inspect was nice because it's like in a factory where the chief "inspects" that everything has been alright.
The name should work independently of the name of the 'then()' function. on_exception? if_exception? catch_all? capture? e.catch_all(eh); And maybe catching/capturing an exception type at a time. e.catch_one<E1>(e1).catch_one<E2>(e2).catch_all<EA>(eh); e.capture<E1>(e1).capture<E2>(e2).capture<all>(eh); But a C++ try/catch is not worst, or is it? try { v=e.get(); } catch(E1 & ex) { e1(ex); } catch(E2 & ex) { e2(ex); } catch(...) {} Best, Vicente
On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote:
Le 28/04/13 18:27, Pierre T. a écrit :
On 04/28/2013 05:20 PM, Vicente J. Botet Escriba wrote:
Le 28/04/13 16:22, Pierre T. a écrit :
On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote:
Le 27/04/13 09:39, Pierre T. a écrit :
On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote: > * Default Constructor or constructor from nullexpect > What is the advantage of having a expected instance that doesn't > have > neither a value nor an exception? > How would the user manages with this possibility? > Are you looking to make expect movable? > Basically, I noticed that classes without default constructor (or default state) are burdensome to use. Indeed, you cannot store an expected in a class as a member if not initialized in the constructor. Or doing something like:
expected<int> e; if(…) else(…) return e;
Through, I removed the default constructor because I found it unclear. I use a nullexcept because it was a good idea in Boost.Optional with nullopt. Yes it was one. But the definition of optional is there to allow a state that means value not present. expected<> is designed to have a value or an exception. Could you answer to the question How would the user manages with this possibility? By testing == nullexcept (operator== not in the proposal, sorry), however you are right, expected must contains an exception or a value. On the other hand, it's nice to provide a default constructor, so an idea could be to add a method "unitialized_error()" in the trait class. Why do you need a default constructor. Because it can be useful for the following situation:
expected<T> func(bool b) { expected<T> e; if(b) { e = f(); // use e } else { e = g(); // use e } return e; }
Some programmers prefer to have only one return statement instead of having:
expected<T> func(bool b) { if(b) { expected<T> e = f(); // use e return e; } else { expected<T> e = g(); // use e return e; } }
Humm, I don't know if this is enough. I'll drop the default constructor for the moment. When an implementation will be available, feedback from users will help to find relevant use-cases.
Finally, I'm not sure to understand how it's related to the movable ability of Boost.Expected.
I let you try to define move move semantics for expected and you will see why this is related. After thinking more on this the moved object could present its exception_ptr if it has one, so move semantics doesn't force to have an uninitialized expected<> Not sure to get it,
expected(expected&& e) // nothing in the initializer list because we don't know if we must move T or Error. { if(has_value) // move value else // move error }
In case T or Error haven't a default constructor, the previous code can't work, right ? You would need to move construct using placement new
new (&value_) T(forward<T>(val)) ;
BTW, exception_ptr move is equivalent to a copy, isn't it?
It is, but expected may store any Error types and not only exception. Adding a trait method "default_error" would help if the Error hasn't a default constructor.
Could we add a dummy field in the union such as:
union{ T value, Error error, bool internal_uninitialized}; I don't think this is a good ideea.
But I'm not sure it's what you meant.
> *Ah I think I see now what was the initial intention. I suspect > that you mean that as the result of e.then(f) would transport the > exception stored on e if e is not valid, then the exception would > be relayed until there is a call to visit_error and no call to > any function will be done.
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); }
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor);
when_all could return a expected
> or something more specific so that then would extract the members of the tuple to call h with two parameters. This start to look more and more like the proposal for futures (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf)
Sorry for the poor explanations about it, but you guessed correctly. I read the futures proposal and the ideas in there are really interesting. However because expected is not related to the time, I think we could just do the following:
e.then(f, g).then(h).inspect(error_inspector)
where "then" takes an unlimited number of functions. In this case it would return a tuple-wrapper class specific to the expected class (in case users would like to store tuple inside expected). Humm, in the example I gave above f an g are not continuations but expected<> producers. Anyway, the variadic version of then could have its uses. I like it, but it is orthogonal to the when_all feature.
What do you think about letting the continuation returning an expected<>? It has the advantage to allowing the continuation to transport exceptions also without throwing.
I forgot to claim the change but in my "then" version, the function passed to "then" must return an expected (or void). So all functions are expected producers. It's strange to return something else because it would always be a good value into an expected. The "then" chaining could not return error cases. I don't think there are much differences between when_all and then(f,g). However, I propose to let this feature out of the GSoC proposal. But of course, we wouldn't let it out of the summer, it's just because time is lacking and adding features in a hurry could break the proposal consistency.
About the "inspect" method, I try to find another name instead of visit_error because it makes me think to the pattern visitor which is too specific to hierarchy classes. I found that inspect was nice because it's like in a factory where the chief "inspects" that everything has been alright.
The name should work independently of the name of the 'then()' function. Oh nice remark.
on_exception? if_exception? catch_all? capture?
e.catch_all(eh);
And maybe catching/capturing an exception type at a time.
e.catch_one<E1>(e1).catch_one<E2>(e2).catch_all<EA>(eh);
e.capture<E1>(e1).capture<E2>(e2).capture<all>(eh);
But a C++ try/catch is not worst, or is it?
try { v=e.get(); } catch(E1 & ex) { e1(ex); } catch(E2 & ex) { e2(ex); } catch(...) {}
I would say "on_error", so it would be a generic name for error type that aren't exception. Thanks again, Pierre T.
Le 28/04/13 20:17, Pierre T. a écrit : > On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote: >> Le 28/04/13 18:27, Pierre T. a écrit : >>> On 04/28/2013 05:20 PM, Vicente J. Botet Escriba wrote: >>>> Le 28/04/13 16:22, Pierre T. a écrit : >>>>> On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote: >>>>>> Le 27/04/13 09:39, Pierre T. a écrit : >>>>>>> On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote: >>>>>>>> * Default Constructor or constructor from nullexpect >>>>>>>> What is the advantage of having a expected instance that doesn't >>>>>>>> have >>>>>>>> neither a value nor an exception? >>>>>>>> How would the user manages with this possibility? >>>>>>>> Are you looking to make expect movable? >>> >> Humm, I don't know if this is enough. > I'll drop the default constructor for the moment. When an > implementation will be available, feedback from users will help to > find relevant use-cases. >>>>>>> >>>>>>>>>>> >>>>>>>>>>>> *Ah I think I see now what was the initial intention. I >>>>>>>>>>>> suspect >>>>>>>>>>>> that you mean that as the result of e.then(f) would >>>>>>>>>>>> transport the >>>>>>>>>>>> exception stored on e if e is not valid, then the exception >>>>>>>>>>>> would >>>>>>>>>>>> be relayed until there is a call to visit_error and no call to >>>>>>>>>>>> any function will be done. >>>>>>>> >>>>>>> >> Humm, in the example I gave above f an g are not continuations but >> expected<> producers. >> Anyway, the variadic version of then could have its uses. I like it, but >> it is orthogonal to the when_all feature. >> >> What do you think about letting the continuation returning an >> expected<>? It has the advantage to allowing the continuation to >> transport exceptions also without throwing. >> > I forgot to claim the change but in my "then" version, the function > passed to "then" must return an expected (or void). So all functions > are expected producers. It's strange to return something else because > it would always be a good value into an expected. The "then" chaining > could not return error cases. > > I don't think there are much differences between when_all and then(f,g). There are some :) * when_all() is a free function, expected::then is a member function. * when_all() takes expected as parameters, while then() takes continuations having as parameter the expected value. They have in common that the result could be an expected. > > However, I propose to let this feature out of the GSoC proposal. But > of course, we wouldn't let it out of the summer, it's just because > time is lacking and adding features in a hurry could break the > proposal consistency. You could add them as COULD features if there is enough time (not on plan). I would prefer if these features were in the priority SHOULD. BTW, could you classify the features of your proposal as MUST/SHOULD/COULD? > >>> About the "inspect" method, I try to find another name instead of >>> visit_error because it makes me think to the pattern visitor which is >>> too specific to hierarchy classes. I found that inspect was nice >>> because it's like in a factory where the chief "inspects" that >>> everything has been alright. >>> >> The name should work independently of the name of the 'then()' function. > Oh nice remark. >> >> on_exception? if_exception? catch_all? capture? >> >> >> > I would say "on_error", so it would be a generic name for error type > that aren't exception. > > yes, why not? Best, Vicente
On 04/28/2013 09:31 PM, Vicente J. Botet Escriba wrote: > Le 28/04/13 20:17, Pierre T. a écrit : >> On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote: >>> Le 28/04/13 18:27, Pierre T. a écrit : >>>> On 04/28/2013 05:20 PM, Vicente J. Botet Escriba wrote: >>>>> Le 28/04/13 16:22, Pierre T. a écrit : >>>>>> On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote: >>>>>>> Le 27/04/13 09:39, Pierre T. a écrit : >>>>>>>> On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote: >>>>>>>>> * Default Constructor or constructor from nullexpect >>>>>>>>> What is the advantage of having a expected instance that doesn't >>>>>>>>> have >>>>>>>>> neither a value nor an exception? >>>>>>>>> How would the user manages with this possibility? >>>>>>>>> Are you looking to make expect movable? >>>> >>> Humm, I don't know if this is enough. >> I'll drop the default constructor for the moment. When an >> implementation will be available, feedback from users will help to >> find relevant use-cases. >>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>>> *Ah I think I see now what was the initial intention. I >>>>>>>>>>>>> suspect >>>>>>>>>>>>> that you mean that as the result of e.then(f) would >>>>>>>>>>>>> transport the >>>>>>>>>>>>> exception stored on e if e is not valid, then the exception >>>>>>>>>>>>> would >>>>>>>>>>>>> be relayed until there is a call to visit_error and no call to >>>>>>>>>>>>> any function will be done. >>>>>>>>> >>>>>>>> >>> Humm, in the example I gave above f an g are not continuations but >>> expected<> producers. >>> Anyway, the variadic version of then could have its uses. I like it, but >>> it is orthogonal to the when_all feature. >>> >>> What do you think about letting the continuation returning an >>> expected<>? It has the advantage to allowing the continuation to >>> transport exceptions also without throwing. >>> >> I forgot to claim the change but in my "then" version, the function >> passed to "then" must return an expected (or void). So all functions >> are expected producers. It's strange to return something else because >> it would always be a good value into an expected. The "then" chaining >> could not return error cases. >> >> I don't think there are much differences between when_all and then(f,g). > There are some :) > * when_all() is a free function, expected::then is a member function. > * when_all() takes expected as parameters, while then() takes > continuations having as parameter the expected value. > > They have in common that the result could be an expected. IMHO, a member method is better because it can be chained any where in the chain. I also prefer the method taking continuations as it enables void return function. >> >> However, I propose to let this feature out of the GSoC proposal. But >> of course, we wouldn't let it out of the summer, it's just because >> time is lacking and adding features in a hurry could break the >> proposal consistency. > You could add them as COULD features if there is enough time (not on > plan). I would prefer if these features were in the priority SHOULD. > BTW, could you classify the features of your proposal as MUST/SHOULD/COULD? Of course, it's an excellent idea. I'll try to update my proposal by tomorrow. >> >>>> About the "inspect" method, I try to find another name instead of >>>> visit_error because it makes me think to the pattern visitor which is >>>> too specific to hierarchy classes. I found that inspect was nice >>>> because it's like in a factory where the chief "inspects" that >>>> everything has been alright. >>>> >>> The name should work independently of the name of the 'then()' function. >> Oh nice remark. >>> >>> on_exception? if_exception? catch_all? capture? >>> >>> >>> >> I would say "on_error", so it would be a generic name for error type >> that aren't exception. >> >> > yes, why not? > > Best, > Vicente > Best regards, Pierre T.
Le 28/04/13 20:17, Pierre T. a écrit :
I forgot to claim the change but in my "then" version, the function passed to "then" must return an expected (or void). So all functions are expected producers. It's strange to return something else because it would always be a good value into an expected. The "then" chaining could not return error cases.
I don't think there are much differences between when_all and then(f,g).
There are some :) * when_all() is a free function, expected::then is a member function. * when_all() takes expected as parameters, while then() takes continuations having as parameter the expected value.
They have in common that the result could be an expected<tuple>. IMHO, a member method is better because it can be chained any where in
On 04/28/2013 09:31 PM, Vicente J. Botet Escriba wrote: the chain. I also prefer the method taking continuations as it enables void return function. I suspect that you have not understood the differences. Each function
Le 28/04/13 22:24, Pierre T. a écrit : provides a different service, they are not concurrent, we don't need to choose one or the other, both are useful. The single thing we can do is to give it a priority on the plan. Vicente
On Apr 28, 2013, at 2:17 PM, "Pierre T."
On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote:
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); }
When the chain gets long, try blocks make increasing sense.
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor);
"if_all" seems better than "when_all". [snip]
I think we could just do the following:
e.then(f, g).then(h).inspect(error_inspector)
"inspect" doesn't carry much meaning in context. [snip]
About the "inspect" method, I try to find another name instead of visit_error because it makes me think to the pattern visitor which is too specific to hierarchy classes. I found that inspect was nice because it's like in a factory where the chief "inspects" that everything has been alright.
The name should work independently of the name of the 'then()' function. Oh nice remark.
+1
on_exception? if_exception? catch_all? capture?
e.catch_all(eh);
And maybe catching/capturing an exception type at a time.
e.catch_one<E1>(e1).catch_one<E2>(e2).catch_all<EA>(eh);
e.capture<E1>(e1).capture<E2>(e2).capture<all>(eh);
But a C++ try/catch is not worst, or is it?
try { v=e.get(); } catch(E1 & ex) { e1(ex); } catch(E2 & ex) { e2(ex); } catch(...) {}
I would say "on_error", so it would be a generic name for error type that aren't exception.
"on_error" seems fine. It reminds me, however, of functions overloaded to take system_error to avoid exceptions. IOW, rather than passing a function, one passes the exception type to collect the error. ___ Rob (Sent from my portable computation engine)
Le 28/04/13 23:28, Rob Stewart a écrit :
On Apr 28, 2013, at 2:17 PM, "Pierre T."
wrote: On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote:
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); } When the chain gets long, try blocks make increasing sense. Agreed.
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor); "if_all" seems better than "when_all".
+1. Vicente
On 04/29/2013 08:11 AM, Vicente J. Botet Escriba wrote:
Le 28/04/13 23:28, Rob Stewart a écrit :
On Apr 28, 2013, at 2:17 PM, "Pierre T."
wrote: On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote:
Yes this is quite similar if we had exceptions and we had a try/catch block
f0().then(f1).then(f2).then(f3).visit_error(error_visitor);
try { f3(f2(f1(f0()))); } catch(...) { error_visitor(); } When the chain gets long, try blocks make increasing sense. Agreed. Right, but we can work with non-exception based error.
It would be great if we could have the equivalent for try { h(f(), g()); } catch(...) { error_visitor(); }
when_all(f(), g()).then(h).visit_error(error_visitor); "if_all" seems better than "when_all".
+1. +1 too. But I'd like to keep the "then" taking more than one function.
e.then(h).then(f, g).then(h2).on_error(error_resolver); try{ h2(f(h()), g(h())); } catch(…) { error_resolver(); } The goal would be to enable any function composition.
Vicente
Best regards, Pierre T.
Le 29/04/13 08:29, Pierre T. a écrit :
On 04/29/2013 08:11 AM, Vicente J. Botet Escriba wrote:
Le 28/04/13 23:28, Rob Stewart a écrit :
On Apr 28, 2013, at 2:17 PM, "Pierre T."
wrote: On 04/28/2013 07:30 PM, Vicente J. Botet Escriba wrote:
> Yes this is quite similar if we had exceptions and we had a > try/catch block > > f0().then(f1).then(f2).then(f3).visit_error(error_visitor); > > try { > f3(f2(f1(f0()))); > } catch(...) { > error_visitor(); > } When the chain gets long, try blocks make increasing sense. Agreed. Right, but we can work with non-exception based error. An example with exception and non-exception would be welcome.
> It would be great if we could have the equivalent for > try { > h(f(), g()); > } catch(...) { > error_visitor(); > } > > when_all(f(), g()).then(h).visit_error(error_visitor); "if_all" seems better than "when_all".
+1. +1 too. But I'd like to keep the "then" taking more than one function.
e.then(h).then(f, g).then(h2).on_error(error_resolver);
try{ h2(f(h()), g(h())); } catch(…) { error_resolver(); }
The goal would be to enable any function composition.
Great. Vicente
Hello, I put my proposal on google-melange: https://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trad... Badly, I have troubles with the html formatting because we can't easily add CSS and because the CSS of the page interferes with the html code. It's the result of converting a latex file into a html file. So please follow the link in the additional info to get a good PDF version. Do you think I need to format by hand the proposal or does the link to the pdf is enough? Any comments and suggestions would be appreciated. Thanks, Pierre Talbot
Pierre T. wrote
Hello,
I put my proposal on google-melange:
https://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trad...
Badly, I have troubles with the html formatting because we can't easily add CSS and because the CSS of the page interferes with the html code. It's the result of converting a latex file into a html file. So please follow the link in the additional info to get a good PDF version.
Do you think I need to format by hand the proposal or does the link to the pdf is enough?
Yes. I would prefer if you can provide a proposal that is well formatted in addition to your pdf file. Note that not all the mentors would open the pdf file when evaluating your proposal.
Any comments and suggestions would be appreciated.
Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/gsoc-2013-Boost-Expected-tp4645271p464635... Sent from the Boost - Dev mailing list archive at Nabble.com.
On 04/30/2013 07:00 PM, Vicente Botet wrote:
Pierre T. wrote
Hello,
I put my proposal on google-melange:
https://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trad...
Badly, I have troubles with the html formatting because we can't easily add CSS and because the CSS of the page interferes with the html code. It's the result of converting a latex file into a html file. So please follow the link in the additional info to get a good PDF version.
Do you think I need to format by hand the proposal or does the link to the pdf is enough?
Yes. I would prefer if you can provide a proposal that is well formatted in addition to your pdf file. Note that not all the mentors would open the pdf file when evaluating your proposal.
I entirely reformatted it. I think is much more readable now.
Any comments and suggestions would be appreciated.
Best, Vicente
Best regards, Pierre T.
Hi,
2013/5/1 Pierre T.
On 04/30/2013 07:00 PM, Vicente Botet wrote:
Pierre T. wrote
Hello,
I put my proposal on google-melange:
https://google-melange.**appspot.com/gsoc/proposal/** review/google/gsoc2013/**trademark/25002https://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trad...
Badly, I have troubles with the html formatting because we can't easily add CSS and because the CSS of the page interferes with the html code. It's the result of converting a latex file into a html file. So please follow the link in the additional info to get a good PDF version.
Do you think I need to format by hand the proposal or does the link to the pdf is enough?
Yes. I would prefer if you can provide a proposal that is well formatted in addition to your pdf file. Note that not all the mentors would open the pdf file when evaluating your proposal.
I entirely reformatted it. I think is much more readable now.
I didn't follow this thread closely, but have you consider an implicit convert operator to value_type? e.g. expected<SomeType> f(); SomeType var = f(); // throws on error It's most intuitive to me.
Le 01/05/13 18:27, TONGARI a écrit :
I didn't follow this thread closely, but have you consider an implicit convert operator to value_type? e.g.
expected<SomeType> f();
SomeType var = f(); // throws on error
It's most intuitive to me.
We need to choose between an explicit conversion to bool and an implicit (or explict) conversion to value_type, otherwise there would be a conflict when the value_type is bool. I prefer particularly the explicit bool conversion. This is in line with the optional design. BTW, the following is not so ugly. SomeType var = f().value(); // throws on error Best, Vicente
On Wed, May 1, 2013 at 5:33 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 01/05/13 18:27, TONGARI a écrit :
I didn't follow this thread closely, but have you consider an implicit
convert operator to value_type? e.g.
expected<SomeType> f();
SomeType var = f(); // throws on error
It's most intuitive to me.
We need to choose between an explicit conversion to bool and an implicit (or explict) conversion to value_type, otherwise there would be a conflict when the value_type is bool. I prefer particularly the explicit bool conversion. This is in line with the optional design. BTW, the following is not so ugly.
SomeType var = f().value(); // throws on error
Best, Vicente
Let's not use optional as the pinnacle of design just yet. optional<bool> in particular. I'm concerned about: optional<bool> ob = false; if (ob) // true, as optional is 'engaged' ... if (ob == false) // true (I think) as optional<T>==(T) is used ... so bool(ob) != (ob == true). ( Or if I misunderstand the ordering of conversion-to-bool vs operator==, or optional<bool>::operator==(bool) was explicitly disallowed, then you would have a problem with optional in generic contexts: optional<SomeType> opt = ...; if (opt == SomeType(val)) ... does this behave differently when SomeType == bool vs SomeType == int? ) I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now) Tony
Le 02/05/13 00:29, Gottlob Frege a écrit :
On Wed, May 1, 2013 at 5:33 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 01/05/13 18:27, TONGARI a écrit :
I didn't follow this thread closely, but have you consider an implicit
convert operator to value_type? e.g.
expected<SomeType> f();
SomeType var = f(); // throws on error
It's most intuitive to me.
We need to choose between an explicit conversion to bool and an implicit (or explict) conversion to value_type, otherwise there would be a conflict when the value_type is bool. I prefer particularly the explicit bool conversion. This is in line with the optional design. BTW, the following is not so ugly.
SomeType var = f().value(); // throws on error
Best, Vicente
Let's not use optional as the pinnacle of design just yet. optional<bool> in particular. I'm concerned about:
optional<bool> ob = false;
if (ob) // true, as optional is 'engaged' This as I understand it. ... if (ob == false) // true (I think) as optional<T>==(T) is used ...
so bool(ob) != (ob == true). Hrr, this is really surprising.
I guess the pragmatic solution is to remove also the explicit conversion to bool and use an explicit valid() function if (ob) // compile fail if (ob.valid()) // true, as optional is 'engaged' if (ob == true) // true as optional<T>==(T) is used The same seems to be applicable to expected.
( Or if I misunderstand the ordering of conversion-to-bool vs operator==, or optional<bool>::operator==(bool) was explicitly disallowed, I don't see nothing in http://isocpp.org/files/papers/N3672.html
then you would have a problem with optional in generic contexts:
optional<SomeType> opt = ...;
if (opt == SomeType(val)) ...
does this behave differently when SomeType == bool vs SomeType == int? )
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now)
Agreed. I could try the std-proposal forum or c++std-lib-ext@accu.org if you don't mind. Coming back to the OP, expected is a type to avoid to throw exceptions. It would be surprising to me that an exception could be thrown by an implicit conversion. Are there others that think that implicit conversion to ValueType is a good thing to have? What makes expected so different from optional to have a different design? Vicente
On 05/02/2013 02:23 AM, Vicente J. Botet Escriba wrote:
Le 02/05/13 00:29, Gottlob Frege a écrit :
On Wed, May 1, 2013 at 5:33 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 01/05/13 18:27, TONGARI a écrit :
I didn't follow this thread closely, but have you consider an implicit
convert operator to value_type? e.g.
expected<SomeType> f();
SomeType var = f(); // throws on error
It's most intuitive to me.
We need to choose between an explicit conversion to bool and an implicit (or explict) conversion to value_type, otherwise there would be a conflict when the value_type is bool. I prefer particularly the explicit bool conversion. This is in line with the optional design. BTW, the following is not so ugly.
SomeType var = f().value(); // throws on error
Best, Vicente
Let's not use optional as the pinnacle of design just yet. optional<bool> in particular. I'm concerned about:
optional<bool> ob = false;
if (ob) // true, as optional is 'engaged' This as I understand it. ... if (ob == false) // true (I think) as optional<T>==(T) is used ...
so bool(ob) != (ob == true). Hrr, this is really surprising.
I guess the pragmatic solution is to remove also the explicit conversion to bool and use an explicit valid() function
if (ob) // compile fail
if (ob.valid()) // true, as optional is 'engaged'
if (ob == true) // true as optional<T>==(T) is used
The same seems to be applicable to expected.
( Or if I misunderstand the ordering of conversion-to-bool vs operator==, or optional<bool>::operator==(bool) was explicitly disallowed, I don't see nothing in http://isocpp.org/files/papers/N3672.html
then you would have a problem with optional in generic contexts:
optional<SomeType> opt = ...;
if (opt == SomeType(val)) ...
does this behave differently when SomeType == bool vs SomeType == int? )
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now)
Agreed. I could try the std-proposal forum or c++std-lib-ext@accu.org if you don't mind.
Coming back to the OP, expected is a type to avoid to throw exceptions. It would be surprising to me that an exception could be thrown by an implicit conversion.
Are there others that think that implicit conversion to ValueType is a good thing to have? What makes expected so different from optional to have a different design?
Vicente
An expected is just a optional which have an error status when disengage. If expected is standardized in the future, it would be best to keep the same behaviour with the implicit/explicit cast as optional. Otherwise, I'm pretty sure it would lead to frustrating error from users using both. Pierre T.
On Thu, May 2, 2013 at 5:05 AM, Pierre T.
An expected is just a optional which have an error status when disengage. If expected is standardized in the future, it would be best to keep the same behaviour with the implicit/explicit cast as optional. Otherwise, I'm pretty sure it would lead to frustrating error from users using both.
Pierre T.
Yes, I agree it should be the same. Just note that optional isn't actually standardized yet and there will still be some changes before it is. Also, I think expected<> helps clarify optional's interface, as it applies the interface to additional coding patterns - so it can help with some of the changes that will happen to optional between now and the final C++14. Tony
On Wed, May 1, 2013 at 8:23 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 02/05/13 00:29, Gottlob Frege a écrit :
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now)
Agreed. I could try the std-proposal forum or c++std-lib-ext@accu.org if you don't mind.
You of course could, but I think std-proposal and the committee has probably had enough of optional for a while. I think the next best step is a paper clearly showing all the issues and offering clear recommendations/options.
Coming back to the OP, expected is a type to avoid to throw exceptions. It would be surprising to me that an exception could be thrown by an implicit conversion.
Are there others that think that implicit conversion to ValueType is a good thing to have? What makes expected so different from optional to have a different design?
I don't think it should be different from optional. But expected *is* different than optional - look at the name. You could argue that "expected" implies that you really did expect the value to be there, so implicit conversion would not be, well, unexpected. Whereas optional means the value is optional - being disengaged is just as expected as being engaged, thus implicit conversion of optional might not be as expected. But overall, I think the consistency is more important. You could also argue that optional should have implicit conversion, since it has already started down the road of "act like T" via things like the mixed relational operators. But I worry about implicit conversions (in general) and I'd rather not bring up any changes to optional that are just design decisions (vs issues of incompleteness or "unintended consequences"). So overall I _lean_ towards no implicit conversion, but I can see both sides of it.
Vicente
Tony
Le 02/05/13 16:17, Gottlob Frege a écrit :
On Wed, May 1, 2013 at 8:23 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 02/05/13 00:29, Gottlob Frege a écrit :
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now)
Agreed. I could try the std-proposal forum or c++std-lib-ext@accu.org if you don't mind.
You of course could, but I think std-proposal and the committee has probably had enough of optional for a while. I think the next best step is a paper clearly showing all the issues and offering clear recommendations/options.
Coming back to the OP, expected is a type to avoid to throw exceptions. It would be surprising to me that an exception could be thrown by an implicit conversion.
Are there others that think that implicit conversion to ValueType is a good thing to have? What makes expected so different from optional to have a different design?
I don't think it should be different from optional.
But expected *is* different than optional - look at the name. You could argue that "expected" implies that you really did expect the value to be there, so implicit conversion would not be, well, unexpected. Whereas optional means the value is optional - being disengaged is just as expected as being engaged, thus implicit conversion of optional might not be as expected.
But overall, I think the consistency is more important.
You could also argue that optional should have implicit conversion, since it has already started down the road of "act like T" via things like the mixed relational operators. But I worry about implicit conversions (in general) and I'd rather not bring up any changes to optional that are just design decisions (vs issues of incompleteness or "unintended consequences").
So overall I _lean_ towards no implicit conversion, but I can see both sides of it.
+1 Vicente
On May 2, 2013, at 10:17 AM, Gottlob Frege
On Wed, May 1, 2013 at 8:23 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 02/05/13 00:29, Gottlob Frege a écrit :
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve.
+1
Coming back to the OP, expected is a type to avoid to throw exceptions. It would be surprising to me that an exception could be thrown by an implicit conversion.
Are there others that think that implicit conversion to ValueType is a good thing to have?
I think it could prove handy, but may cause unintended consequences.
What makes expected so different from optional to have a different design? I don't think it should be different from optional.
They should be similar so long as the similarity isn't forced.
But expected *is* different than optional - look at the name. You could argue that "expected" implies that you really did expect the value to be there, so implicit conversion would not be, well, unexpected.
That is reasonable.
Whereas optional means the value is optional - being disengaged is just as expected as being engaged, thus implicit conversion of optional might not be as expected.
Agreed.
But overall, I think the consistency is more important.
"A foolish consistency is the hobgoblin of little minds." I'm not suggesting you're being foolish or that you have a little mind. I mean only to caution against making consistency, among unrelated types, too important.
You could also argue that optional should have implicit conversion, since it has already started down the road of "act like T" via things like the mixed relational operators.
I'd argue against it.
But I worry about implicit conversions (in general)
+1
and I'd rather not bring up any changes to optional that are just design decisions (vs issues of incompleteness or "unintended consequences").
I agree with that sentiment, but I also don't want the wrong thing enshrined in the standard.
So overall I _lean_ towards no implicit conversion, but I can see both sides of it.
I think there's a good case for no implicit conversion for optional and having it for expected. However, omitting it for both is safer and satisfies the consistency wish. ___ Rob (Sent from my portable computation engine)
I suspect both optional<bool> and expected<bool> will be somewhat common uses (considering the number of tri-bool classes in existence), so I think this is a real problem that we need to resolve. (And I expect to write up something after BoostCon/C++Now)
Agreed. I could try the std-proposal forum or c++std-lib-ext@accu.orgif you don't mind.
You of course could, but I think std-proposal and the committee has probably had enough of optional for a while. I think the next best step is a paper clearly showing all the issues and offering clear recommendations/options.
So I advised against bringing it up... and then I brought it up on std-proposal myself. (Well, the existing conversation just went in that direction...) Oh well. Some day I'll learn to listen to my own advice.
participants (10)
-
Gottlob Frege
-
Klaim - Joël Lamotte
-
Krzysztof Czainski
-
Michael Marcin
-
Pierre T.
-
Rob Stewart
-
Steven Watanabe
-
TONGARI
-
Vicente Botet
-
Vicente J. Botet Escriba