RE: [boost] [optional]output

----Original Message---- From: Gennadiy Rozental [mailto:gennadiy.rozental@thomson.com] Sent: 07 March 2005 07:18 To: boost@lists.boost.org Subject: [boost] [optional]output
Hi,
Maybe it's something that I missed, but why optional doesn't define output operator something like this:
template<typename T> inline std::ostream& operator<<( std::ostream& ostr, optional<T> const& v ) { if( v ) ostr << *v; return ostr; }
I don't think optional should define an output operator at all. There are too many possibly useful definitions. For example: template<typename T> inline std::ostream& operator<<( std::ostream& ostr, optional<T> const& v ) { if( v ) { ostr << true << ' ' << *v; } else { ostr << false; } return ostr; } -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434

"Martin Bonner" <martin.bonner@pitechnology.com> wrote in message news:E562FCEE3A42D61192880002A5FB433302D7A929@kite.pigroup.co.uk...
----Original Message---- From: Gennadiy Rozental [mailto:gennadiy.rozental@thomson.com] Sent: 07 March 2005 07:18 To: boost@lists.boost.org Subject: [boost] [optional]output
Hi,
Maybe it's something that I missed, but why optional doesn't define output operator something like this:
template<typename T> inline std::ostream& operator<<( std::ostream& ostr, optional<T> const& v ) { if( v ) ostr << *v; return ostr; }
I don't think optional should define an output operator at all. There are too many possibly useful definitions. For example:
template<typename T> inline std::ostream& operator<<( std::ostream& ostr, optional<T> const& v ) { if( v ) { ostr << true << ' ' << *v; } else { ostr << false; } return ostr; }
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not. Anyone is free to implement function for custom printing, but I believe default should behave the way I describe above. BTW optional<T> currently is streamable , but it prints 1 or 0 - initialized status - obviously bad choice for output semantic. Gennadiy

Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost.

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:00f501c52404$bff4fca0$6501a8c0@pdimov...
Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost.
1. This is not exactly true Output most probably will look like: a, , v, c, d, , Which should be enough to restore it back 2. Why should I bother at all? In my opinion "able to restore" is not primary concern for output operators. I know numerous cases where result of operator<< couldn't be read back. Serialization of optional<T> does need to care about that. Gennadiy

Gennadiy Rozental wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in message news:00f501c52404$bff4fca0$6501a8c0@pdimov...
Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost.
1. This is not exactly true
Output most probably will look like:
a, , v, c, d, ,
Which should be enough to restore it back
The usual way to read vector<X> _today_ is istream_iterator<X> first( is ), last; vector<X> v( first, last ); It only works with whitespace as a separator.

Output most probably will look like:
a, , v, c, d, ,
Which should be enough to restore it back
The usual way to read vector<X> _today_ is
istream_iterator<X> first( is ), last; vector<X> v( first, last );
It only works with whitespace as a separator.
Maybe we need to remedy this hmm... inflexibility. How about boost::istream_iterator that wraps token_iterator and accepts separator? Gennadiy

"Peter Dimov" <pdimov@mmltd.net> writes:
Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost.
Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Printing something only for empty optional may lead to unclear output. For example what should be an output of: optional<string> v = "empty"; optional<string> v; optional<bool> v = false; optional<bool> v; optional<int> v = 0; optional<int> v; Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Printing something only for empty optional may lead to unclear output. For example what should be an output of:
optional<string> v = "empty"; optional<string> v;
optional<bool> v = false; optional<bool> v;
optional<int> v = 0; optional<int> v;
Nothing. ;-)
Gennadiy
But seriously, folks, any output is confusible. Just pick a sufficiently unlikely placeholder string. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Tue, 08 Mar 2005 15:42:36 -0500, David Abrahams <dave@boost-consulting.com> wrote:
"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Printing something only for empty optional may lead to unclear output. For example what should be an output of:
optional<string> v = "empty"; optional<string> v;
optional<bool> v = false; optional<bool> v;
optional<int> v = 0; optional<int> v;
Nothing. ;-)
Gennadiy
But seriously, folks, any output is confusible. Just pick a sufficiently unlikely placeholder string.
How about: () (empty) (false) (0) or something similar? Bruno

David Abrahams <dave <at> boost-consulting.com> writes:
"Gennadiy Rozental" <gennadiy.rozental <at> thomson.com> writes:
Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Printing something only for empty optional may lead to unclear output. For example what should be an output of:
optional<string> v = "empty"; optional<string> v;
optional<bool> v = false; optional<bool> v;
optional<int> v = 0; optional<int> v;
Nothing.
Gennadiy
But seriously, folks, any output is confusible. Just pick a sufficiently unlikely placeholder string.
How about using SML-like option-type notation: SOME(empty) SOME(false) SOME(0) NONE so in general template<typename T> std::ostream& operator<<(std::ostream& out, boost::optional<T> const& t_option) { if (t_option) { out << "SOME(" << *t_option << ")"; } else { out << "NONE"; } return out; } -Ryan

David Abrahams wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost.
Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Perhaps do as the tuples do? [123] <- a non-empty optional<int> [] <- an empty optional<T> Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
David Abrahams wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
Gennadiy Rozental wrote:
I believe this version is much less intuitive. optional<T> v is still value of type T which may or may not be present. Accordingly when we print it we print the value if it present or print nothing if it not.
This isn't very useful. The output cannot be read back, and when printing a sequence of optionals much of the information is lost. Agreed. I was going to say that an empty optional should print something, but couldn't articulate the reasons. Thanks.
Perhaps do as the tuples do?
[123] <- a non-empty optional<int> [] <- an empty optional<T>
If you want to be unambiguous, it has to be more like: [hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T> -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
My preference is hello _ A string can never be output "correctly", no matter what the delimiters are ("a] [b"). I'd concentrate on making optional<X> (reasonably) bi-directional when X is bi-directional.

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
My preference is
hello
_
A string can never be output "correctly", no matter what the delimiters are ("a] [b").
I disagree. You can generate escapes: [a\] \[b] or if you like, [a\]\ \[b] -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
My preference is
hello
_
A string can never be output "correctly", no matter what the delimiters are ("a] [b").
I disagree. You can generate escapes:
[a\] \[b]
or if you like,
[a\]\ \[b]
I should have been more clear. You shouldn't attempt to fix the output of a std::string in optional<>'s operator<<. The proper way to make a std::string bi-directional is by defining appropriate operator<< and operator>> overloads for std::string. As these operators are already defined and are not bi-directional in the general case, optional<std::string> should not attempt to provide extra bi-directionality. I would concentrate on making simple bi-directional types working correctly, and outputting a placeholder token such as _ for an empty optional is one way to accomplish this that produces a reasonably clear output (although it requires a putback, which is sadly not guaranteed to work).

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
My preference is
hello
_
A string can never be output "correctly", no matter what the delimiters are ("a] [b").
I disagree. You can generate escapes:
[a\] \[b]
or if you like,
[a\]\ \[b]
I should have been more clear. You shouldn't attempt to fix the output of a std::string in optional<>'s operator<<. The proper way to make a std::string bi-directional is by defining appropriate operator<< and operator>> overloads for std::string. As these operators are already defined and are not bi-directional in the general case, optional<std::string> should not attempt to provide extra bi-directionality.
Okay, I don't neccessarily disagree, but I don't agree yet either. Why? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
I should have been more clear. You shouldn't attempt to fix the output of a std::string in optional<>'s operator<<. The proper way to make a std::string bi-directional is by defining appropriate operator<< and operator>> overloads for std::string. As these operators are already defined and are not bi-directional in the general case, optional<std::string> should not attempt to provide extra bi-directionality.
Okay, I don't neccessarily disagree, but I don't agree yet either. Why?
When a type's operator<< is "broken", you can't fix it from the outside. struct X { std::string data; }; ostream& operator<< ( ostream& os, X const & x ) { return os << x.data; } It is not reasonable to expect all types that rely on string::<< to fix it to match your (arbitrary, I might add) convention.

"Peter Dimov" <pdimov@mmltd.net> writes:
When a type's operator<< is "broken", you can't fix it from the outside.
I wasn't trying to fix it from the outside; I was trying to give optional a way of unambiguously indicating emptiness.
struct X { std::string data; };
ostream& operator<< ( ostream& os, X const & x ) { return os << x.data; }
It is not reasonable to expect all types that rely on string::<< to fix it to match your (arbitrary, I might add) convention.
So what? I don't see what bearing it has. I could buy into the argument that optional will always print ambiguously anyway, since optional<char const*>("123") and optional<int>(123) will print the same text. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> escribió en el mensaje news:uwtsgbzti.fsf@boost-consulting.com...
"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
My preference is
hello
_
A string can never be output "correctly", no matter what the delimiters are ("a] [b").
I disagree. You can generate escapes:
[a\] \[b]
or if you like,
[a\]\ \[b]
Well, I hope that by now it is obvious why I didn't add this operator to begin with. Since it can always be added externally in the context of the client code, I simply decided to let her/him do that, using whatever format suits in that context. But I suppose I could provide *some* IO even if imperfect. I see 2 distinct purposes for operator << One is to provide a readable output, the other some form of serialization. Given that we have the serialization library, I believe it is (or has to be) its job to provide a suitable encoding scheme to fully "textualize" and "parse" an optional<T>. Specially since to parse it back you may also need to encode the type. If I would only focus on providing a readable output, I would take Peter's suggestion and simply use "_" or some such as a textual empty optional<>. However, this totally breaks any chance to parse it. Ryan's suggestion supports parsing, and so does Joel's, which is much terser, so I like it better. But I agree with David that his suggested format is even less ambiguous. Therefore, so far, I'm taking Joel's + David's proposal: It supports some form of simple parsing (if you know the type) and provides a somewhat readable output as well. [<text>] A non-empty optional<T> with value: lexical_cast<T>(<text>) <text> can be an empty string _ An empty optional<T> Best, Fernando Cacciola

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Perhaps do as the tuples do?
[123] <- a non-empty optional<int> [] <- an empty optional<T>
If you want to be unambiguous, it has to be more like:
[hello] <- a non-empty optional<std::string> [] <- a non-empty optional<std::string> (the string is empty) _ <- an empty optional<T>
Nice! I think the variant needs to follow. What does variant do? Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (8)
-
Bruno Martínez Aguerre
-
David Abrahams
-
Fernando Cacciola
-
Gennadiy Rozental
-
Joel de Guzman
-
Martin Bonner
-
Peter Dimov
-
Ryan Gallagher