
On Feb 25, 2009, at 8:21 AM, Alexander Nasonov wrote:
Andrew, sorry for the late reply.
Don't worry about it, I seem to remember you've been otherwise busy with something just a tad bit more important ;)
optional<T> is about initialized versus uninitialized value, it has nothing to do with stream's state. IMO, the failbit should be set.
My vision of optional<T> streaming is based on this quote from documentation:
"optional<T> intends to formalize the notion of initialization (or lack of it) allowing a program to test whether an object has been initialized and stating that access to the value of an uninitialized object is undefined behavior."
Thus, - after a successful read the stream is in a good state and the value is initialized, - after read failure, the failbit bit is set and the value is uninitialized, - printing of initialized optional<T> value produces the same result as printing T value,
That's what you might expect, but in fact printing optional<T> is not the same as printing T. Printing optional<T> is the same as printing " " + T. An extra space is added before the value of T.
- printing of uninitialized value sets the failbit.
Again, things are not as you might expect. Printing optional<T> when uninitialized shows "--" and does not set the failbit. I find this particularly odd and would certainly prefer either the failbit being set as you say, or for optional<T> to not be OutputStreamable at all.
My streaming proposal makes lexical_cast < optional<T> >(v) equivalent to lexical_cast<T>(v) because it would never return uninitialized value. I can use it as a good excuse for implementing no-throw version of lexical_cast < optional<T> >(v) ;-)
Sorry it's been a while, which proposal where? Wouldn't implementing a no-throw version of lexical_cast for optional<T> necessarily couple lexical_cast and Boost.Optional? In related news, I was briefly contacted by Fernando Cacciola (author of Boost.Optional) who provided me with some insight about why optional_io.hpp is the way it is. I hesitate to post verbatim a private email I received from him on this mailing list, but I can summarize what I learned. Near the first of this month he informed me that optional_io.hpp initially came from the Serialization library and its requirements were mainly directed by that. I had proposed (and still do propose) this change to optional_io.hpp's operator<<(): if (in) { T x; if (in >> x) { v = x; } else { if (in.fail () && !in.eof ()) { in.clear (); in.get (); } v = optional<T> (); } } else { v = optional<T> (); } return in; He agreed that it would work given my requirements, but said he wouldn't dare change it without bringing in Robert Ramey to the discussion, an author of Boost.Serialization and the original author of the code in question. I wrote Robert soon thereafter with my concerns but unfortunately I never heard back from him. Since it's been some time, allow me to make more clear my reasoning for this refinement. Does the following seem a little weird to anyone else? stringstream sin ("test"); optional<string> token; sin >> token; // token remains uninitialized. // But if sin had " test", // then *token would be "test" And this: optional<string> s; cout << s; // shows "--" But... isn't "--" a valid string? Essentially, I think it would be optimal if streaming optional types behaved as much like streaming the types they wrap as possible. And since optional types can be in an uninitialized state, it seems reasonable that failing to extract one from a stream should simply return an uninitialized optional type without setting the failbit on the stream. Think about it this way: Isn't an uninitialized optional<T> a valid optional<T>? And the failbit got set because we attempted to extract *optional<T>::value_type* from the stream and couldn't. Does that mean we failed to extract an optional<T>? What we failed to extract is a T. Except we're returning a valid optional<T> even in this case. I think that means we actually succeeded in extracting an optional<T>! Sure it's uninitialized, but that's ok for an optional type. I would also like to add that I like your idea that "printing of uninitialized value sets the failbit." That seams a very reasonable improvement as well. But the catch is, I have no idea how these changes would impact the Serialization library. Robert, if you're out there, would you care to weigh in? -- Andrew Troschinetz Applied Research Laboratories