**semantics**:
template< typename left_type, typename right_type>
struct either
{
// postcondition, is_left()
either( left_type );
// postcondition, is_right()
either( right_type );
bool is_left() const;
bool is_right() const;
// postcondition, is_left()
either & operator=( left_type );
// postcondition, is_right()
either & operator=( right_type );
// precondition, is_left()
left_type left();
// precondition, is_right()
right_type right();
private:
};
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error
codes+set reference idiom):
either
Hi, it is not clear to me how it is "lightweight" compared to boost::variant, can you clarify? Joel Lamotte
On Fri, Jun 21, 2013 at 11:19 AM, Klaim - Joël Lamotte
it is not clear to me how it is "lightweight" compared to boost::variant, can you clarify?
Less syntactic overhead for the case when you'd like to get the left or right value out of it. See use 2 in the original email. David Sankel
On Fri, Jun 21, 2013 at 12:35 PM, David Sankel
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
There was also talk of an 'expected' class for this case (where one of the 2 choices was the, well, expected one). I'm still hoping for that class. Although it may be syntactically the same as 'either', I appreciate its explicit intentions. I'm not sure if that makes 'either' less needed, and means variant + expected ( + optional, etc) is enough. Tony
On Sat, Jun 22, 2013 at 2:07 AM, Bjorn Reese
You may want to check the GSoC 2013 proposal for Boost.Expected:
http://google-melange.appspot.**com/gsoc/proposal/review/** google/gsoc2013/trademark/**25002http://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trade... http://github.com/**TrademarkPewPew/Boost.Expectedhttp://github.com/TrademarkPewPew/Boost.Expected
Thanks for the pointer.
On Fri, Jun 21, 2013 at 2:55 PM, Gottlob Frege
On Fri, Jun 21, 2013 at 12:35 PM, David Sankel
wrote: **Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
There was also talk of an 'expected' class for this case (where one of the 2 choices was the, well, expected one). I'm still hoping for that class. Although it may be syntactically the same as 'either', I appreciate its explicit intentions. I'm not sure if that makes 'either' less needed, and means variant + expected ( + optional, etc) is enough.
To summarize my understanding of how 'Boost.Expected' relates 'either': They are semantically equivalent, but the former using naming conventions and default values that imply one particular use case, the return error condition one. Maybe std::map should be using a specialized 'KeyValue' instead of std::pair, but I personally think that in both map's case and in the error returning case the types are simple enough that a convention would be sufficient. David Sankel
On 21/06/13 18:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
What happens if the 'either' originally contained a right_type and that the copy/move constructor of left_type throws?
On Fri, Jun 21, 2013 at 4:42 PM, Mathias Gaunard < mathias.gaunard@ens-lyon.org> wrote:
On 21/06/13 18:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
What happens if the 'either' originally contained a right_type and that the copy/move constructor of left_type throws?
Good question. I think the tradeoffs that were made with Boost.Variant in that case would work just as well here. David Sankel
On Sun, Jun 23, 2013 at 5:07 AM, Mathias Gaunard < mathias.gaunard@ens-lyon.org> wrote:
On 22/06/13 15:11, David Sankel wrote:
Good question. I think the tradeoffs that were made with Boost.Variant in
that case would work just as well here.
Don't you already have an implementation? What does it do?
I do, now that you ask, at https://github.com/camio/Boost.Either. This reference implementation uses Boost.Variant as a back-end and thus inherits a lot of its behavior. Let me try to summarize what precisely happens in the case you were originally inquiring upon (what happens with exceptions in assignments): 1. For types where this can happen, the resulting state will still have all the invariants of the either type met. That is, it will always refer to either a 'left' or a 'right' value. 2. Because of point one, the use of internal types that have throwing assignments may incur an allocation during these operations in order to ensure #1 is met. 3. Ways will be provided to workaround the overhead in #2 for capable types. More details here: http://www.boost.org/doc/libs/1_49_0/doc/html/variant/design.html#variant.de... -- David Sankel
On 06/21/2013 06:35 PM, David Sankel wrote:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
You may want to check the GSoC 2013 proposal for Boost.Expected: http://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trade... http://github.com/TrademarkPewPew/Boost.Expected
On 06/21/13 11:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); vs.
error_code load_file( file_id &, ... );
or
// throws std::exception file_id load_file(...);
Isn't this like haskell's either: http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Eith... which also has been suggested as a semi-replacement for exceptions: http://www.haskell.org/pipermail/haskell-cafe/2004-August/006549.html which uses the terms expected and unexpected, which might explain the name expected used in the proposed Boost.Expected library mentioned in Bjorn Reese's reply. I remember seeing elsewhere that haskell's either was mentioned as a replacement for exceptions. I see if I can find it. -regards, Larry
On 06/22/13 10:17, Larry Evans wrote:
On 06/21/13 11:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { [snip] **uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); [snip] Isn't this like haskell's either:
http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Eith...
[snip]
I remember seeing elsewhere that haskell's either was mentioned as a replacement for exceptions. I see if I can find it. Googling "haskell either exceptions" turned up:
http://book.realworldhaskell.org/read/error-handling.html which, under: Use of Either talks about using either to handle errors. -regards, Larry
Hi Larry!
On Sat, Jun 22, 2013 at 9:17 AM, Larry Evans
On 06/21/13 11:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); vs.
error_code load_file( file_id &, ... );
or
// throws std::exception file_id load_file(...);
Isn't this like haskell's either:
http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Eith...
Yes. The proposed nomenclature (either, left, right) is intentionally mimicking that of Haskell. I remember seeing elsewhere that haskell's either was mentioned as
a replacement for exceptions. I see if I can find it.
The Either Monad is commonly used for this purpose among others ( http://hackage.haskell.org/packages/archive/category-extras/0.53.1/doc/html/... ). David Sankel
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of David Sankel Sent: Saturday, June 22, 2013 6:47 PM To: boost@lists.boost.org Subject: Re: [boost] Interest in an 'either' library?
Hi Larry!
On Sat, Jun 22, 2013 at 9:17 AM, Larry Evans
wrote: On 06/21/13 11:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); vs.
error_code load_file( file_id &, ... );
or
// throws std::exception file_id load_file(...);
Isn't this like haskell's either:
http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Dat a-Either.html
Yes. The proposed nomenclature (either, left, right) is intentionally mimicking that of Haskell.
It's a somewhat cosmetic issue, but I suspect that most of the use cases involve an expected and an unexpected (rather than both being equally likely), so I'm not sure that following Haskell's name is really a good idea? Either way, I'm in favour of this and expect it to be useful ;-) Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com
On Sun, Jun 23, 2013 at 3:52 AM, Paul A. Bristow
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of David Sankel Sent: Saturday, June 22, 2013 6:47 PM To: boost@lists.boost.org Subject: Re: [boost] Interest in an 'either' library?
Hi Larry!
On Sat, Jun 22, 2013 at 9:17 AM, Larry Evans
On 06/21/13 11:35, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); vs.
error_code load_file( file_id &, ... );
or
// throws std::exception file_id load_file(...);
Isn't this like haskell's either:
http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Dat a-Either.html
Yes. The proposed nomenclature (either, left, right) is intentionally mimicking that of Haskell.
It's a somewhat cosmetic issue, but I suspect that most of the use cases involve an expected and an unexpected (rather than both being equally likely), so I'm not sure that following Haskell's name is really a good idea?
The (either, left, right) wording is somewhat arbitrary. I do see some serious problems, though, with the (expected,unexpected) wording because it will mislead readers of code that doesn't use the exception alternative use case. For example, compare the following definition, optional< either< isbn_10, isbn_13 > > parse_isbn_string( std::string ); to the equivalent using the 'expected' wording, optional< expected< isbn_10, isbn_13 > > parse_isbn_string( std::string ); -- David Sankel
Hello
For example, compare the following definition,
optional< either< isbn_10, isbn_13 > > parse_isbn_string( std::string );
to the equivalent using the 'expected' wording,
optional< expected< isbn_10, isbn_13 > > parse_isbn_string( std::string );
I think there is some misunderstanding and confusion between Expected/Optional/Either. Indeed, I'm quite sure that Expected and Either are completely different. Even if Expected seems to be a subset of Either, because you can choose to return a (value, exception/error) couple in Either, the behavior will be different. IMHO, Expected is more useful because it adds a lot of semantics for this particular use-case. I'd say that if Expected is the brother of Optional, Either is the child of Variant (because it's a subset without adding specific semantic). To correct the example above, it should be: optional< either< isbn_10, isbn_13 > > parse_isbn_string( std::string ); OR expected< either< isbn_10, isbn_13 > > parse_isbn_string( std::string ); Depending on the design of parse_isbn_string – if it says or not why the parsing failed. I think Either could be useful in case it's massively used to avoid the syntactic overhead of Variant. Finally, the first argument of this Either library was the error/value couple facilities, but now we know that Expected is quite better, does Either is just syntactic sugar ? Or do you have other relevant use cases ? Best regards, Pierre Talbot
On 06/24/13 06:20, Pierre T. wrote:> Hello [snip]
I think there is some misunderstanding and confusion between Expected/Optional/Either. Indeed, I'm quite sure that Expected and Either are completely different. Even if Expected seems to be a subset of Either, because you can choose to return a (value, exception/error) couple in Either, the behavior will be different. IMHO, Expected is more useful because it adds a lot of semantics for this
Could you please highlight what the semantics are which distinguish Either from Expected?
particular use-case.
I'd say that if Expected is the brother of Optional, Either is the child of Variant (because it's a subset without adding specific semantic).
The gsoc2013 Expected page: http://google-melange.appspot.com/gsoc/proposal/review/google/gsoc2013/trade... says: expected< T,Error > proposed here is a type that contains a type T or a type Error in its storage space. which sounds a lot like the OP passage: **Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom): and a lot like: The Either type is similar to the Maybe type, with one key difference: it can carry attached data both for an error and a success (“the Right answer”). from: http://book.realworldhaskell.org/read/error-handling.html Based on a brief look at: http://www.boost.org/doc/libs/1_53_0/libs/optional/doc/html/boost_optional/d... Boost.Optional is like haskell's Maybe<T>(either a T value or Nothing). The Nothing in haskell's Maybe is like the none_t mentioned on the boost_optional/detailed_semantics.html page mentioned above. Hence, I don't see any fundamental difference between Either and Expected. What am I missing? [snip]
Finally, the first argument of this Either library was the error/value couple facilities, but now we know that Expected is quite better,
Could you explain exactly how Expected is better? [snip] -regards, Larry
On Mon, Jun 24, 2013 at 8:49 AM, Larry Evans
Could you explain exactly how Expected is better?
either
On Mon, Jun 24, 2013 at 5:20 AM, Pierre T.
For example, compare the following definition,
optional< either< isbn_10, isbn_13 > > parse_isbn_string( std::string );
to the equivalent using the 'expected' wording,
optional< expected< isbn_10, isbn_13 > > parse_isbn_string( std::string );
I think there is some misunderstanding and confusion between Expected/Optional/Either. Indeed, I'm quite sure that Expected and Either are completely different. Even if Expected seems to be a subset of Either, because you can choose to return a (value, exception/error) couple in Either, the behavior will be different. IMHO, Expected is more useful because it adds a lot of semantics for this particular use-case.
I think the misunderstanding is between the precise meanings of syntax and semantics. The expected class and the either class are *semantically* equivalent. That is, if we map them to their precise mathematical meanings, they are the same. [[either]] = A + B = [[expected]] (I'm using ADT syntax here for the mathematical domain (see: http://cpp-next.com/archive/2010/07/algebraic-data-types/)). They are *syntactically* different in that different names were chosen.
I'd say that if Expected is the brother of Optional, Either is the child of Variant (because it's a subset without adding specific semantic).
I have no idea what you mean by 'brother' and 'child'. To correct the example above, it should be:
optional< either< isbn_10, isbn_13 > > parse_isbn_string( std::string );
OR
expected< either< isbn_10, isbn_13 > > parse_isbn_string( std::string );
Depending on the design of parse_isbn_string – if it says or not why the parsing failed.
Okay, I think you've made it clear that you'd like to limit the application of expected to a particular use case that isn't implied by the semantics, but only by the author's intention. This is a bad design strategy IMO. A good reusable library will be documented by its semantics primarily and provide use-cases to give the user hints of where it will be useful (but never limit the user by the author's necessarily limited foresight)
I think Either could be useful in case it's massively used to avoid the syntactic overhead of Variant.
Finally, the first argument of this Either library was the error/value couple facilities, but now we know that Expected is quite better, does Either is just syntactic sugar ? Or do you have other relevant use cases ?
I don't think it has been demonstrated that "expected is quite better". There are plenty of use cases for either because it is such a fundamental type. Here are just a few handy generic functions (using Haskell type syntax for conciseness): either :: (a -> c) -> (b -> c) -> Either a b -> c partitionEithers :: [Either a b] -> ([a], [b]) mapEither :: (a -> Either b c) -> IntMap a -> (IntMap b, IntMap c) lefts :: [Either a b] -> [a] rights :: [Either a b] -> [b] liftRight :: a -> Either a b liftLeft :: a -> Either b a David
I think the misunderstanding is between the precise meanings of syntax and semantics. The expected class and the either class are *semantically* equivalent. That is, if we map them to their precise mathematical meanings, they are the same. [[either]] = A + B = [[expected]] (I'm using ADT syntax here for the mathematical domain (see: http://cpp-next.com/archive/2010/07/algebraic-data-types/)).
They are *syntactically* different in that different names were chosen.
Mathematically speaking, ok there are semantically equivalent, I got it now (BTW thanks for the link, I learned something).
Okay, I think you've made it clear that you'd like to limit the application of expected to a particular use case that isn't implied by the semantics, but only by the author's intention.
This is a bad design strategy IMO. A good reusable library will be documented by its semantics primarily and provide use-cases to give the user hints of where it will be useful (but never limit the user by the author's necessarily limited foresight)
Indeed, the Expected class was firstly designed for error reporting. We can generalize it for an Either class but we lose some contexts that would have helped to simplify this reporting in C++. Maybe we can propose free functions over Either to handle this specific use case, but I don't know how well it will work.
I think Either could be useful in case it's massively used to avoid the syntactic overhead of Variant.
Finally, the first argument of this Either library was the error/value couple facilities, but now we know that Expected is quite better, does Either is just syntactic sugar ? Or do you have other relevant use cases ?
I don't think it has been demonstrated that "expected is quite better". There are plenty of use cases for either because it is such a fundamental type. Here are just a few handy generic functions (using Haskell type syntax for conciseness):
either :: (a -> c) -> (b -> c) -> Either a b -> c partitionEithers :: [Either a b] -> ([a], [b]) mapEither :: (a -> Either b c) -> IntMap a -> (IntMap b, IntMap c) lefts :: [Either a b] -> [a] rights :: [Either a b] -> [b] liftRight :: a -> Either a b liftLeft :: a -> Either b a
David
On Tue, Jun 25, 2013 at 1:28 AM, Pierre Talbot
A good reusable library will be
documented by its semantics primarily and provide use-cases to give the
user hints of where it will be useful (but never limit the user by the author's necessarily limited foresight)
Indeed, the Expected class was firstly designed for error reporting. We can generalize it for an Either class but we lose some contexts that would have helped to simplify this reporting in C++. Maybe we can propose free functions over Either to handle this specific use case, but I don't know how well it will work.
Now we're talking! Lets come up with the best free-function error-reporting use case functions we can and see if they are so horrible they're worth making all the other use cases look broken. --David Sankel
On 21 Jun 2013 17:36, "David Sankel"
**Use 2**: A lightweight alternative to boost::variant when only 2 components are required (either relates to variant in a similar way that pair relates to tuple ). (...)
either eitherAOrB;
if( eitherAOrB.is_left() ) std::cout << "A: " << eitherAOrB.left(); else std::cout << "B: " << eitherAOrB.right();
Is there any particular reason not to follow std::pair naming and use first() and second() members? Regards, -- Mateusz Loskot (Sent from mobile, apology for top-posting and broken quotes)
On 23/06/13 13:45, Mateusz Loskot wrote:
On 21 Jun 2013 17:36, "David Sankel"
wrote: **Use 2**: A lightweight alternative to boost::variant when only 2 components are required (either relates to variant in a similar way that pair relates to tuple ). (...)
either eitherAOrB;
if( eitherAOrB.is_left() ) std::cout << "A: " << eitherAOrB.left(); else std::cout << "B: " << eitherAOrB.right();
Is there any particular reason not to follow std::pair naming and use first() and second() members?
first()/second() implies a sequence with at least two elements.
On 23 Jun 2013 13:12, "Mathias Gaunard"
On 23/06/13 13:45, Mateusz Loskot wrote:
On 21 Jun 2013 17:36, "David Sankel"
wrote: **Use 2**: A lightweight alternative to boost::variant when only 2 components are required (either relates to variant in a similar way that pair relates to tuple ). (...)
either eitherAOrB;
if( eitherAOrB.is_left() ) std::cout << "A: " << eitherAOrB.left(); else std::cout << "B: " << eitherAOrB.right();
Is there any particular reason not to follow std::pair naming and use first() and second() members?
first()/second() implies a sequence with at least two elements.
Good point, thanks. -- Mateusz Loskot, http://mateusz.loskot.net
On 6/21/2013 9:35 AM, David Sankel wrote:
**semantics**:
template< typename left_type, typename right_type> struct either { // postcondition, is_left() either( left_type );
// postcondition, is_right() either( right_type );
bool is_left() const; bool is_right() const;
// postcondition, is_left() either & operator=( left_type );
// postcondition, is_right() either & operator=( right_type );
// precondition, is_left() left_type left();
// precondition, is_right() right_type right(); private: };
**uses**:
**Use 1**: Can be used as an alternative to exceptions or the (error codes+set reference idiom):
either
load_file(...); vs.
error_code load_file( file_id &, ... );
or
// throws std::exception file_id load_file(...);
**Use 2**: A lightweight alternative to boost::variant when only 2 components are required (either relates to variant in a similar way that pair relates to tuple ).
vs.
either eitherAOrB;
if( eitherAOrB.is_left() ) std::cout << "A: " << eitherAOrB.left(); else std::cout << "B: " << eitherAOrB.right();
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error. I implemented something like this. Check out substitution_failure and try_call starting here: https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h... -- Eric Niebler Boost.org http://www.boost.org
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea. Actually, the "then" method can be applied on an expected and immediately returns the expected if it contains an error. Furthermore, you can chain function calls until one of these fail. Here one of the use-case shown in the proposal: expected<int> create_and_connect() { return socket() // call the function socket that creates an expected. .then(connect) // Pass the expected handle to connect if it contains a value, otherwise just returns it. .on_error(error_resolver); // Use the error_resolver if the last expected contains an error, otherwise just returns it. } There is maybe two advantages to this then function: * Chaining multiple calls. * A specific error resolver in case of failure. But it doesn't offer multiple argument check, and that's why we also proposed if_all: if_all(f(), g()).then(h).on_error(error_resolver); I think this one is much more related to your function. I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
On 13-06-24 11:53 AM, Pierre Talbot wrote:
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea.
Glad it's been considered!
Actually, the "then" method can be applied on an expected and immediately returns the expected if it contains an error. Furthermore, you can chain function calls until one of these fail.
Here one of the use-case shown in the proposal:
expected<int> create_and_connect() { return socket() // call the function socket that creates an expected. .then(connect) // Pass the expected handle to connect if it contains a value, otherwise just returns it. .on_error(error_resolver); // Use the error_resolver if the last expected contains an error, otherwise just returns it. }
There is maybe two advantages to this then function:
* Chaining multiple calls. * A specific error resolver in case of failure.
But it doesn't offer multiple argument check, and that's why we also proposed if_all:
if_all(f(), g()).then(h).on_error(error_resolver);
I think this one is much more related to your function.
I'm not sure that hits the mark. What if you want to call h with the results of calling f and g, but only if f() and g() return non-errors? That is, what would this look like in your proposed system: // if h or g fails, h return immediately. h(f(), "hello world", g(), 42); I'm partial to this: // if h or g fails, h return immediately. try_call(h)(f(), "hello world", g(), 42);
I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
Seems a bit excessive to me to have both. If we get Expected, then Either is unnecessary -- it's just one template alias away from variant. I don't consider the syntactic niceties of "left" and "right" to be compelling, and if folks want it, we can provide left and right free functions for 2-arg variants. But IMO automatic error propagation is the *only* thing that can make this proposal compelling. And while I'm thinking of it, I see lots of potential with try_call and C++14's generic lambdas. Wish I had a compiler that implements them. In the above, if h is not something that can be passed as a parameter, you'd want this: try_call([](auto &&...args){return h(forward<decltype-dance>(args)...);})(f(), "hello world", g(), 42); This begs to be wrapped up in a macro. -- Eric Niebler Boost.org
On Mon, Jun 24, 2013 at 1:19 PM, Eric Niebler
On 13-06-24 11:53 AM, Pierre Talbot wrote:
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea.
<snip various do-syntax derivatives>
If we really care about adding a do syntax EDSL, why not make it general
purpose like Haskell's version so that it can work with any monad and
compose better with other things?
either
I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
Seems a bit excessive to me to have both. If we get Expected, then Either is unnecessary -- it's just one template alias away from variant. I don't consider the syntactic niceties of "left" and "right" to be compelling, and if folks want it, we can provide left and right free functions for 2-arg variants. But IMO automatic error propagation is the *only* thing that can make this proposal compelling.
I personally find myself using std::pair frequently even though it is also just one template alias away from std::tuple. I still think there's a case for exposing these commonly-useful simple building blocks. Incidentally, the std::pair monad is also interesting. David
On 06/24/13 22:55, David Sankel wrote:
On Mon, Jun 24, 2013 at 1:19 PM, Eric Niebler
wrote: On 13-06-24 11:53 AM, Pierre Talbot wrote:
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea.
<snip various do-syntax derivatives>
If we really care about adding a do syntax EDSL, why not make it general purpose like Haskell's version so that it can work with any monad and compose better with other things?
either
result = do( set( _x, getInt ), set( _y, getInt ), doReturn( pure( _x + _y ) ) ); If we're going to do that, lets do it generically and completely.
+1 David, is there source code demonstrating this do syntax? Could you show how to do Eric's example with this do syntax? -regards, Larry
On Tue, Jun 25, 2013 at 8:27 AM, Larry Evans
On 06/24/13 22:55, David Sankel wrote:
On Mon, Jun 24, 2013 at 1:19 PM, Eric Niebler
wrote: On 13-06-24 11:53 AM, Pierre Talbot wrote:
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful
if
there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea.
<snip various do-syntax derivatives>
If we really care about adding a do syntax EDSL, why not make it general purpose like Haskell's version so that it can work with any monad and compose better with other things?
either
result = do( set( _x, getInt ), set( _y, getInt ), doReturn( pure( _x + _y ) ) ); If we're going to do that, lets do it generically and completely.
+1
David, is there source code demonstrating this do syntax?
I haven't made a library. That was off the top of my head.
Could you show how to do Eric's example with this do syntax?
Eric's example was:
// if h or g fails, h return immediately.
try_call(h)(f(), "hello world", g(), 42);
Using do syntax, something like...
do(
set( _fResult, f ),
set( _gResult, g ),
doReturn( app( h, _fResult, "hello world", _gResult, 42 ) ) );
Well, actually this improves efficiency, if f has an 'error' then g won't
be evaluated.
But, the more I think of this, the more I think something like indices
would work very well here. _1 would refer to the result of the first
statement, _2 the result of the second, etc. I also prefer the 'pure'
moniker instead of 'return' for taking a non-wrapped value and putting it
into a wrapped one.
do(
app( f ),
app( g ),
pure( app( h, _1, "hello world", _2, 42 ) ) );
This works with the following:
either
On 6/24/2013 8:55 PM, David Sankel wrote:
On Mon, Jun 24, 2013 at 1:19 PM, Eric Niebler
wrote: On 13-06-24 11:53 AM, Pierre Talbot wrote:
This misses what is, IMO, the most important use case of Haskell's Either monad: automatic error propagation. This would be more useful if there were a way to call a function such that if any of the function's arguments were an Either-in-error, the function would immediately return the error.
I implemented something like this. Check out substitution_failure and try_call starting here:
https://github.com/ericniebler/proto-0x/blob/master/boost/proto/v5/utility.h...
In the Expected proposal, there are some methods related to this idea.
<snip various do-syntax derivatives>
If we really care about adding a do syntax EDSL, why not make it general purpose like Haskell's version so that it can work with any monad and compose better with other things?
either
result = do( set( _x, getInt ), set( _y, getInt ), doReturn( pure( _x + _y ) ) ); If we're going to do that, lets do it generically and completely.
I've been giving serious thought to that recently. The problem with it, however, is that it requires the use of Phoenix-style lambda expressions like "_x + _y". (I can only assume you mean for _x and _y to be placeholders and not actual values. I can't think of another way to implement this.) It seems that for such core functionality, we don't want to be saddled by Phoenix's syntax and compile-times, but maybe I'm wrong. Anyhow, yes, I think something like this should exists. Phoenix could provide one implementation. FWIW, I just pushed another monad-in-c++ up to my github last night (the first link is the state monad, the second is an example that uses it): https://github.com/ericniebler/fpxx/blob/master/include/fpxx/monad/state.hpp https://github.com/ericniebler/fpxx/blob/master/example/state.cpp But I don't think this obviates the need for the try_call that I was suggesting. It is extremely light-weight and let's people write ordinary C++ instead of Phoenix. And I think it would be easier to teach to C++ programmers.
I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
Seems a bit excessive to me to have both. If we get Expected, then Either is unnecessary -- it's just one template alias away from variant. I don't consider the syntactic niceties of "left" and "right" to be compelling, and if folks want it, we can provide left and right free functions for 2-arg variants. But IMO automatic error propagation is the *only* thing that can make this proposal compelling.
I personally find myself using std::pair frequently even though it is also just one template alias away from std::tuple. I still think there's a case for exposing these commonly-useful simple building blocks. Incidentally, the std::pair monad is also interesting.
I use it too. But I tend to believe that if C++ got std::tuple first, std::pair really would just be a template alias for a 2-tuple. That's obviously just my opinion, though. -- Eric Niebler Boost.org http://www.boost.org
On Tue, Jun 25, 2013 at 9:18 AM, Eric Niebler
On 6/24/2013 8:55 PM, David Sankel wrote:
If we really care about adding a do syntax EDSL, why not make it general purpose like Haskell's version so that it can work with any monad and compose better with other things?
either
result = do( set( _x, getInt ), set( _y, getInt ), doReturn( pure( _x + _y ) ) ); If we're going to do that, lets do it generically and completely.
I've been giving serious thought to that recently. The problem with it, however, is that it requires the use of Phoenix-style lambda expressions like "_x + _y". (I can only assume you mean for _x and _y to be placeholders and not actual values. I can't think of another way to implement this.) It seems that for such core functionality, we don't want to be saddled by Phoenix's syntax and compile-times, but maybe I'm wrong.
I think the 'index' syntax would work around the issues with both unfamiliarity (people already know bind) and phoenix compilation times.
Anyhow, yes, I think something like this should exists. Phoenix could provide one implementation. FWIW, I just pushed another monad-in-c++ up to my github last night (the first link is the state monad, the second is an example that uses it):
https://github.com/ericniebler/fpxx/blob/master/include/fpxx/monad/state.hpp https://github.com/ericniebler/fpxx/blob/master/example/state.cpp
Cool. I hope you gave bind and '>>' names so they can be used in higher
order functions.
Let me give that do notation I mentioned in the earlier email a better
definition:
do( stmt1, stmt2, stmt3 ).
Do will return some monad parameterized by a type A. stmt1 will define that
type.
Every statement will be an expression that returns a monadic value
(assuming a monadic context). Here are the expression possibilities:
-
suggesting. It is extremely light-weight and let's people write ordinary C++ instead of Phoenix. And I think it would be easier to teach to C++ programmers.
I dunno, it looks pretty odd to me. Do notation seems both simpler and more powerful. (Just to note for other readers, I tend to write complex examples to illustrate the power - simple things remain simple though)
I honestly think that if Either goes into Boost, we shouldn't consider
it as a value or error structure at all. Expected (will) do the job.
Seems a bit excessive to me to have both. If we get Expected, then Either is unnecessary -- it's just one template alias away from variant. I don't consider the syntactic niceties of "left" and "right" to be compelling, and if folks want it, we can provide left and right free functions for 2-arg variants. But IMO automatic error propagation is the *only* thing that can make this proposal compelling.
I personally find myself using std::pair frequently even though it is also just one template alias away from std::tuple. I still think there's a case for exposing these commonly-useful simple building blocks. Incidentally, the std::pair monad is also interesting.
I use it too. But I tend to believe that if C++ got std::tuple first, std::pair really would just be a template alias for a 2-tuple. That's obviously just my opinion, though.
I'm down for making either a template alias for a 2-variant where the 2-variant has special names to give easy access to left and right. -- David Sankel
On Wed, Jun 26, 2013 at 11:47 AM, Gottlob Frege
On Wed, Jun 26, 2013 at 12:21 PM, David Sankel
wrote: Let me give that do notation I mentioned in the earlier email a better definition:
do( stmt1, stmt2, stmt3 ).
I don't think C++ guarantees the order of those statements. Is that a problem?
No. The actual evaluation of those expressions (which can be though of as 'lazy'), if they are evaluated a all, will occur in the body of the do function in the correct order. C++ expressions, of course, will be evaluated before the do function is entered, but this shouldn't cause any issues. David
On 25/06/13 17:18, Eric Niebler wrote:
either
result = do( set( _x, getInt ), set( _y, getInt ), doReturn( pure( _x + _y ) ) ); If we're going to do that, lets do it generically and completely.
I've been giving serious thought to that recently. The problem with it, however, is that it requires the use of Phoenix-style lambda expressions like "_x + _y". (I can only assume you mean for _x and _y to be placeholders and not actual values. I can't think of another way to implement this.) It seems that for such core functionality, we don't want to be saddled by Phoenix's syntax and compile-times, but maybe I'm wrong.
The following Haskell syntax, transliterated to C++ do ( x, result = y, foo(result) ); is syntactic sugar for x >> y >>= [](auto result) { return foo(result); }; or even x >>= [](auto) { return y >>= [](auto result) { return foo(result); }; }; if you want to avoid specializing statements with no result. I think it is important to distinguish the support for this sugar and the monad system itself. The monad system itself is just implementing the >>= operator for the given monad type. As a matter of fact this sugar can even be implemented with macros. The syntax above is possible with minor adjustments.
On Mon, Jun 24, 2013 at 8:19 PM, Eric Niebler
[...] And while I'm thinking of it, I see lots of potential with try_call and C++14's generic lambdas. Wish I had a compiler that implements them. In
On 13-06-24 11:53 AM, Pierre Talbot wrote: the above, if h is not something that can be passed as a parameter, you'd want this:
try_call([](auto &&...args){return h(forward<decltype-dance>(args)...);})(f(), "hello world", g(), 42);
This begs to be wrapped up in a macro.
Yet another use case for n3617: try_call([]h)(f(), "hello world", g(), 42); See https://github.com/gpderetta/Experiments/blob/master/tests/quote_test.cc for a C++11 macro based proof-of-concept implementation. -- gpd
On 13-06-25 01:53 AM, Giovanni Piero Deretta wrote:
On Mon, Jun 24, 2013 at 8:19 PM, Eric Niebler
wrote: [...] And while I'm thinking of it, I see lots of potential with try_call and C++14's generic lambdas. Wish I had a compiler that implements them. In
On 13-06-24 11:53 AM, Pierre Talbot wrote: the above, if h is not something that can be passed as a parameter, you'd want this:
try_call([](auto &&...args){return h(forward<decltype-dance>(args)...);})(f(), "hello world", g(), 42);
This begs to be wrapped up in a macro.
Yet another use case for n3617:
try_call([]h)(f(), "hello world", g(), 42);
Oooh, that's nice. Has this been discussed yet in committee?
See https://github.com/gpderetta/Experiments/blob/master/tests/quote_test.cc for a C++11 macro based proof-of-concept implementation.
-- Eric Niebler Boost.org
On Tue, Jun 25, 2013 at 11:14 PM, Eric Niebler
On 13-06-25 01:53 AM, Giovanni Piero Deretta wrote:
On Mon, Jun 24, 2013 at 8:19 PM, Eric Niebler
wrote: [...] And while I'm thinking of it, I see lots of potential with try_call and C++14's generic lambdas. Wish I had a compiler that implements them. In
On 13-06-24 11:53 AM, Pierre Talbot wrote: the above, if h is not something that can be passed as a parameter, you'd want this:
try_call([](auto &&...args){return h(forward<decltype-dance>(args)...);})(f(), "hello world", g(), 42);
This begs to be wrapped up in a macro.
Yet another use case for n3617:
try_call([]h)(f(), "hello world", g(), 42);
Oooh, that's nice. Has this been discussed yet in committee?
See https://github.com/gpderetta/Experiments/blob/master/tests/quote_test.cc for a C++11 macro based proof-of-concept implementation.
As far as I know it hasn't been discussed at last meeting. Not sure whether for lack of time or lack of a sponsor. -- gpd
On 26/06/13 01:24, Giovanni Piero Deretta wrote:
On Tue, Jun 25, 2013 at 11:14 PM, Eric Niebler
wrote: On 13-06-25 01:53 AM, Giovanni Piero Deretta wrote:
On Mon, Jun 24, 2013 at 8:19 PM, Eric Niebler
wrote: [...] And while I'm thinking of it, I see lots of potential with try_call and C++14's generic lambdas. Wish I had a compiler that implements them. In
On 13-06-24 11:53 AM, Pierre Talbot wrote: the above, if h is not something that can be passed as a parameter, you'd want this:
try_call([](auto &&...args){return h(forward<decltype-dance>(args)...);})(f(), "hello world", g(), 42);
This begs to be wrapped up in a macro.
Yet another use case for n3617:
try_call([]h)(f(), "hello world", g(), 42);
Oooh, that's nice. Has this been discussed yet in committee?
See https://github.com/gpderetta/Experiments/blob/master/tests/quote_test.cc for a C++11 macro based proof-of-concept implementation.
As far as I know it hasn't been discussed at last meeting. Not sure whether for lack of time or lack of a sponsor.
Probably lack of a sponsor. It's just syntactic sugar. You could just write INVOKABLE(h), with INVOKABLE a suitably defined macro, to achieve exactly the same thing.
On 06/24/13 13:53, Pierre Talbot wrote: [snip]
In the Expected proposal, there are some methods related to this idea. Actually, the "then" method can be applied on an expected and immediately returns the expected if it contains an error. Furthermore, you can chain function calls until one of these fail.
This sounds similar to the Error Monad described here: http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-erro... The example given there is one where the errors produced are caused by dividing by 0. This can happen in 2 places and the 1st to fail produces an error message. The example code from the above is: divSum3 :: Float -> Float -> Float -> Either String Float divSum3 x y z = do xdy <- myDiv3 x y xdz <- myDiv3 x z return (xdy + xdz) in which xdy or xdz can be zero which causes the error. IIUC, the first one which causes the error causes the propagation of that error to the return. IOW, the above example can be extended to any number of divisors: divSum3 :: Float -> Float -> Float . . . -> Either String Float divSum3 x d1 d2 ... dn = do xd1 <- myDiv3 x d1 xd2 <- myDiv3 x d2 ... xdn <- myDiv3 x dn return (xd1 + xd2 + ... + xdn) Why not use something like haskell's Error Monad to do something similar? Several years ago, I remember a Georgia Tech proposal to do that. IIUC, they also had some sort of c++ monad template. -regards, Larry
On 06/24/2013 08:53 PM, Pierre Talbot wrote:
I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
I completely agree. While I have nothing against Either, I would not want to use it for error handling for various reasons. Apart from the function chaining that you have described, there are also traits that allows you to customize certain aspects for your own error type. There are implicit conversion of values, so the code for the normal case look more clean. With Either you always have to specify the error type, whereas with Expected it can be omitted. With Either you have to adopt a convention about which side is the error code. And different project will adopt different conventions, which means that you cannot know if is_left() checks for the value or the error without looking up the type. In short, I believe that Expected offers a better usability for (non-Haskell) programmers than Either does in the error use case.
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Bjorn Reese Sent: Tuesday, June 25, 2013 12:10 PM To: boost@lists.boost.org Subject: Re: [boost] Interest in an 'either' library?
On 06/24/2013 08:53 PM, Pierre Talbot wrote:
I honestly think that if Either goes into Boost, we shouldn't consider it as a value or error structure at all. Expected (will) do the job.
I completely agree. While I have nothing against Either, I would not want to use it for error handling for various reasons.
Apart from the function chaining that you have described, there are also traits that allows you to customize certain aspects for your own error type.
There are implicit conversion of values, so the code for the normal case look more clean.
With Either you always have to specify the error type, whereas with Expected it can be omitted.
With Either you have to adopt a convention about which side is the error code. And different
adopt different conventions, which means that you cannot know if is_left() checks for the value or
project will the
error without looking up the type.
In short, I believe that Expected offers a better usability for (non-Haskell) programmers than Either does in the error use case.
+1 This is what ordinary users (who are the main customers for this) will want. Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com
participants (12)
-
Bjorn Reese
-
David Sankel
-
Eric Niebler
-
Giovanni Piero Deretta
-
Gottlob Frege
-
Klaim - Joël Lamotte
-
Larry Evans
-
Mateusz Loskot
-
Mathias Gaunard
-
Paul A. Bristow
-
Pierre T.
-
Pierre Talbot