Boost logo

Boost :

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. :-)


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