$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] Boost review of the Convert library is ongoing
From: Vladimir Batov (Vladimir.Batov_at_[hidden])
Date: 2014-05-21 20:04:50
On 05/20/2014 09:15 PM, alex wrote:
>>
>>> Conversion to/from string requires a different contract than
>>> conversion between types, encryption or conversion from Celsius to
>>> Fahrenheit.
>> I fail to see how/why these mentioned different type
>> conversions/transformations "require different contracts".
> Perhaps it is better to say 'would benefit from different contracts'.
>
> For instance:
>
> type-to-type converters would benefit from contracts that specify mechanisms
> for checking for reversibility, loss of precision, overflow, etc.
> type-string converters would benefit from contracts that specify mechanisms
> for giving formatting instructions
> unit-to-unit converters would benefit from all kinds of consistency and
> equivalence test... see the Boost Unit library
> encryptions converters would benefit from contracts that specify mechanisms
> to specify/query encryption strength
I am not arguing against interface/behavior specifications (a.k.a. 
"contracts") for converters. I only feel that "convert"'s purpose is far 
more modest -- to only specify how to deploy various converters and what 
to expect when we do. It seems far beyond my capabilities and expertise 
to come up with "contracts" you listed.
>
>>> The user still needs to supply a Default Construction function it is just
>>> not the default constructor. I can see that this requirement follows from
>>> the stringstream implementation.
>> No, it's not a requirement of std::sstream but rather imposed by
>> boost::convert::from.
>>
> Yes, but why? Isn't the underlying reason that sstream requires a reference?
>
> my_type val;
> stream >> val;
I feel it's a generic converter requirement -- they all need a "place" 
to write the result to. We might say -- every converter for itself. On 
the other hand, that seemed like a generic enough requirement that the 
"framework" might care providing uniformly to every converter.
>
>>> But it does not seem a reasonable
>>> requirement for a generic converter (nor is the requirement of Copy
>>> Constructible). All you can reasonably require is some function that
> creates
>>> a TypeOut from a TypeIn.
>>
Well, I feel you are not avoiding requirements but merely shifting them 
around from boost::convert() down to converters. A converter will still 
need to be able to create and TypeOut instance somehow and in a generic 
way. So, I feel, we'll be back where we are now with the burden of every 
converter having to do it itself.
>
>> I was not able to come up with a better implementation that would not have
>> those requirements. If you have such an implementation, I'll incorporate
>> it gladly.
>>
> How about reducing the API to the following? The only requirement on TypeOut
> would be the requirements put by boost::optional (or your closely related
> result-type).
>
> api.hpp
> #include <boost/optional.hpp>
> namespace boost
> template<typename TypeOut> struct convert
>    template<typename TypeIn, typename Converter>
>    static boost::optional<TypeOut>  from(TypeIn const& in, Converter const&
> converter)
>    {
>       boost::optional<TypeOut> out;
>       converter(in, out);
>       return out;
>    }
> };
> }
>
> In sstream.hpp you would have(with some simplification)
>
> template<typename T> struct convert_default_maker
> {
>    static T make() { return T(); }
> };
That seems like a 0-gain game as we still have all the same requirements 
and all the same code, right? We still ned to be able to create a 
TypeOut instance somehow generically. Although the code above forces 
every converter to do that by themselves, right? Although passing 
boost::optional into a container might have its benefits... I had it at 
one point... will have to re-visit again.
>
> //  in sstream.hpp
> template<TypeIn, TypeOut>
> void boost::basic_stringstream_converter::operator()(const TypeIn& in,
> boost::optional<TypeOut>& out)
> {
>    TypeOut out_value =  boost::convert_default_maker<TypeOut>::make();
>    stream_.str(std::basic_string< char_type>());
>    stream_ << in;
>    stream_ >> out_value;
>    out = boost::make_optional(!stream_.fail(), out_value);
> }
That's something I'll have to think about. What jumps at me though is 
what I'd call "blur of responsibilities" --  now converter not only 
cares for conversion but for allocation as well. Secondly, in the 
current "convert" design converters know nothing about boost::convert 
"framework". The implementation above seems to require the converter to 
know/deploy boost::converter_default_maker which is either part of the 
"convert" infrastructure or converter's own code, i.e. the converter has 
to have either additional "knowledge"/coupling or additional code. In 
both cases I do not like the "additional" bit. :-)