Boost logo

Boost :

Subject: Re: [boost] [optional_io] InputStreamable refinement
From: Fernando Cacciola (fernando.cacciola_at_[hidden])
Date: 2009-03-02 10:10:22


Hi Andrew,

I was in the middle of the pre-vacation rush when this thread started.

Now I'm back from vacations, so I can finally take a serious look into
the subject :)

Your requirement is to be able to do something like this:

istringstream in ("test");
optional<string> s;
assert (s);

It fails with the current "optional_io.hpp" implementation because it
uses an explicit encoding to indicate the initialization state in the
code as a way to guarantee a closed roundtrip conversion from and to an
uninitialized optional *wihtout any dependency on the encoding used by
the underlying type*

That is, the current optional_io.hpp is explicitely not designed to
support your use case. Instead, it is designed to support the following
use case:

optional<T> in = -value_or_empty-

stream << in ;

optional<T> out ;
stream >> out ;

assert( in == out ) ;

> Andrew Troschinetz <ast <at> arlut.utexas.edu> writes:
>> On Feb 26, 2009, at 10:00 AM, Robert Ramey wrote:
>>
>>> The fact that the serialization of optional is implemented and tested
>>> as part of the serialization library is an anomoly. In fact, this
>>> code and test should be moved into the optional library.
>
> Serialization and optional_io have different approaches.

Considering the current "optional_io.h", not really.

> We refuse to
> read/write an uninitialized object

Which is a reasonable requirement in the context of lexical_cast.

> while serialization encode whether
> an object is initialized or not.
>

And so does "optional_io.h"

>> But why move the get pointer up by one? Why one? Does this make sense?
>> I can't provide a reasoning as to why it does, if it does.
>
> Please don't guess about iostream implemenation details. All we need is
> a consistency with underlying type

That's not all.. you also need a way to detect an unitialized value. You
proposal uses extraction failure for that because it works perfectly
fine in the context of lexical_cast since the stream contains
exclusively the given optional (possibly empty) and nothing else. But if
the stream can contain other items then you need an explicit marker.

I don't think both requirements are compatible. Consider the following:

stringstream stream ;

optional<double> ind ; // <= empty

optional<string> ins("123");

stream << ind << ins ;

optional<double> outd ;
optional<string> outd ;

stream >> outd >> outs ;

assert( ind == outd ) ;
assert( ins == outs ) ;

That would fail using your implementation because the stream would only
contain 123 which just coincidentally represents a valid double, so in
the extraction state the string instead of the double will be empty.
This is what happens when failure to extract is used to indicate an
empty optional.

This deeply depends on the encoding detais of the underlying type. For
example, in one of Andrew's use cases, there is a sequence of numbers
and not-numbers. Just incidentally, since not-numbers fail to extract as
numbers, that works.

I recall very well now having this very same discussion on the distant
past. It used to be as you want it, but for the sake of the
serialization library I choose the current semantics, precisely because
as Robert indicated the serialization library doesn't explicitely depend
on Boost.Optional.

Without any explicit dependency, optional<> *itself* needs to provide
roundtrip IO functions not depending on EOF or the encoding details of
the underlying type for uninitialized optionals.

I implemented the IO operators in a separate header precisely to allow
users to provide the other semantics, but that of course doesn't work if
such a header ends up in another general utility like lexical_cast or
the serialization headers.

Off the top of my head, I think the best course of action would be for
you to provide your implementation in "optional_io.h" but within a
separate namespace, like lexical_cast_detail or so, keeping the current
operators untouched.

Then within the lexical_cast function a "using lexical_cast_detail;"
would resolve to the proper IO operators.

HTH

--
Fernando Cacciola
SciSoft Consulting
http://www.scisoft-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk