Boost logo

Boost :

Subject: Re: [boost] [review] string convert
From: Vladimir Batov (vbatov_at_[hidden])
Date: 2011-05-06 06:10:15


> From: "Matt Chambers" <matt.chambers42_at_[hidden]>
> ...
> I agree that in some cases there is no sensible default/fallback value. In
> those cases, the only concern is whether the conversion succeeded, right?
> So optional<T> will work fine for that case, but it would have to be
> renamed so it doesn't conflict with the simple, throwing
> convert_cast<T>(s):
> optional<hamlet_problem> t = optional_convert_to<hamlet_problem>(s);
> This can be in addition to try_convert_to, which would still be useful
> when both the conversion success and the final value (fallback or not) are
> wanted.

Again, my typical concern is twofold -- result of conversion and the return
value (converted or fallback). The following is my typical use-case (note
the second -- to_be -- parameter that you seemingly missed in your example)

optional<hamlet_problem> t = optional_convert_to<hamlet_problem>(s, to_be);

if (!t)
{
    message("Invalid input. Using fallback");
    t = to_be;
}

Given I might have a dozen of configuration parameters read, I would very
much like have it all done with as few lines as possible:

pair<hamlet_problem, bool> res1 = optional_convert_to<hamlet_problem>(s,
to_be);
pair<my_problem, bool> res2 = optional_convert_to<hamlet_problem>(s,
why_bother);

if (!res1.second) message("Invalid input ... Using fallback");
if (!res2.second) message("Invalid input ... Using fallback");

... proceed with res1.first which is to_be;
... proceed with res2.first which is why_bother;

> In an earlier message you wrote this about the try_convert_to method:
>> #5 IMO can. It deploys the Pascal-style parameter passing and
>> modifications. I
>> remember reading Stroustrup (I think) long time ago advising against
>> passing
>> non-const references and I personally agree. That's due to potential
>> confusion
>> and wrong expectations. I am not aware of any function in std and boost
>> doing
>> that. Introducing such a precedent might be a hard-sell.
> If you want a precedent for taking output as a by-reference parameter:
> boost::algorithm::split.

Great. :-)

> Further, I'm not sure how output references could be considered more
> confusing than the output iterators that are ubiquitous in std algorithms.

Stroustrup. "The C++" #7.2 "... functions that modify call-by-reference
arguments can make programs hard to read and should most often be avoided
(but see 21.2.1)". I agree whole-heartedly. The output iterators that you
mention fall in to the exception category covered in 21.2.1. Our fallback
reference not (IMHO). I find the below quite confusing

    int fallback = 1;
    int v1 = convert_to("123", fallback);
    bool converted = try_convert_to<int>("123", fallback);

as convert_to does not and try_convert_to does modify 'fallback'. Again,
that's my preference and, in fact, I believe it's quite a common view (just
see how often modifiable call-by-reference arguments are used).

> Outside the enum case, have you considered that your use of convert on so
> many object types mixes lexical conversion and serialization (admittedly
> related concepts)?

Well, we indeed use lexical conversion to implement serialization, i.e.
conversion to/from textual form. Is it wrong?

Indeed, I was pushing that objectified enum case as an example. Primarily
due to its simplicity. However, where is that edge where a class which
starts as an objectified enumerator acquires enough functionality not to be
considered just an objectified enumerator anymore?

> In my experience, the former uses a simple, concise interface intended for
> value types while the latter uses a verbose interface supporting both
> object types and value types.
> What's the rationale for a lexical conversion library to support
> serialization?

To begin with we use lexical conversion to read from config. files. Spot on
deployment of lexical conversion, right? I am not sure what you describe as
a "simple, concise interface" but we find the interface of lexical_cast to
be just way to clunky and insufficient. For us 'convert' is just right. Once
one has a decent lexical conversion library I am not sure why he needs to
restrict its use to certain cases. After all, a lexical conversion library
takes care of "string-ification" of a class. When an object is
"stringified", I can easily write it to a file, send it over the network,
etc. Then, that object (or rather its copy) is reconstructed from that
respective string. That mentioned lexical conversion library takes care of
that as well and seemingly does it well. I cannot see anything specifically
wrong in deploying a lexical conversion library for the task.

Note: I am glad you mentioned "lexical" and "conversion" together as that's
exactly how I see lexical_cast which pretends to be a cast when it is not
(and I do not like pretenders). It's a converter -- it returns a completely
new instance of a different type when a cast returns the same instance but
retyped (I am aware that upcast returns a different pointer instance for
multiple inheritance). So, I am not thrilled by the latest attempts to
continue that pretending business with convert_cast name (not to mention it
is an oxymoron -- convert and cast are quite different operations). Why
can't things be called as they are -- 'convert' if we are converting, 'cast'
is (and when) we are casting.

Those are merely my views. I am not fighting anyone or anything. I am not
forcing anyone to share those views and not pushing for any particular
interface based on those views. Please proceed as you feel appropriate in
whatever direction you want to proceed.

Best,
V.


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