Boost logo

Boost :

Subject: Re: [boost] [convert] Default Syntax Idea
From: Vladimir.Batov_at_[hidden]
Date: 2009-02-24 17:28:31


> From: "Stewart, Robert" <Robert.Stewart_at_[hidden]>
> I was thinking a bit about syntax for the default value for the
> notional boost::convert() and kin. How about the following:
>
> int const i(3);
> string const s("something");
> int const j(convert<int>(s) | 5);

Yes, this idea is similar to

        int j = convert<int>(s).or_default(5);

but does not introduce new vocabulary (my main hesitation). With the
suggested op|, as I am reading it, it makes perfect reading just like I'd
read English. And that is usually my criterion for an interface. So, I am
voting 'yes'... in principle. See further below.

> convert<DestType,SourceType>(SourceType) can return a type which
> throws on failure in operator DestType(), but has an operator
> |(SourceType) which returns a second type constructed with the
> SourceType value. The second type provides its own operator
> |(SourceType) which returns that value in its operator DestType() on
failure.

When the user does not want comprehensive result, it works. The problem as
I see it is when the user wants the comprehensive report -- we return two
different types,

        convert1<string, int> j1 = convert<string, int>(s);
        convert2<string, int> j2 = convert<string, int>(s) | 5;

Sometimes I feel we need that as I might like to explicitly check if the
call failed without relying on the default

        convert1<string, int> j1 = convert<string, int>(s) &
boost::nothrow;
        convert2<string, int> j2 = convert<string, int>(s) | 5;

        if (j1 == 0 && !j1.good()) j1 = 0 but conversion failed
        if (j2 == 5 && !j1.good()) j2 = 5 but conversion failed

Unless we convert both convert1 and convert2 to convert<string,
int>::result as

        convert<string, int>::result j1 = convert<string, int>(s) &
boost::nothrow;
        convert<string, int>::result j2 = convert<string, int>(s) | 5;

        if (j1 == 0 && !j1.good()) j1 = 0 but conversion failed
        if (j2 == 5 && !j1.good()) j2 = 5 but conversion failed

Or we might simplify that as

        convert::result<int> j1 = convert::to<int>(s) & boost::nothrow;
        convert::result<int> j2 = convert::to<int>(s) | 5;

        if (j1 == 0 && !j1.good()) j1 = 0 but conversion failed
        if (j2 == 5 && !j1.good()) j2 = 5 but conversion failed
 
The reason I am sticking 'to' in again is that I need the 'convert' as a
namespace... or rather as a namespace-like structure:

struct convert : mimic_namespace /*I have such a class*/
{
        template<class TypeOut>
        struct result
        {
                TypeOut value_;
                bool good_;
        };
 
        struct internal_with_default { ... };
        struct internal_with_no_default { ... };

        template<class TypeOut, class TypeIn>
        internal_with_default<TypeOut, TypeIn>
        to(TypeIn const&);
};

With namespace-like convert structure people will not be able to shortcut
'convert'. I.e. they'll always have to say

        convert::to

which is darn close to

        convert_to

with the advantage of having a dedicated namespace-like place instead of
messing inside the boost namespace.

Now it seems like I am back where I started. :-)

> Returning a default value in lieu of an exception is a special case;
> it ought not be treated like formatting.

I have an impression that throwing/not-throwing and
providing/not-providing the default have to be configured independently.
Like I *might* need to throw even if I provide the default:

        direction dir = convert<string, direction>(str, direction::up) &
boost::dothrow;

Above I provide the default because I have to (direction does not have the
def. ctor). However, I still *might* like to throw on failure.

> Thus, while Boost.
> Parameter might be appropriate to package the extra information
> desired for formatting, I don't like the idea of writing "default_ =
> 5" in the call, and I don't think ", 5" in the argument list is as
> clear as it could be.

I tend to agree with you on both.

> The syntax above is obvious and concise while
> being distinct from whatever may be done for formatting.

You meant to say "laconic", right? Oh, just kidding. Thanks for pointing
it out BTW.

BTW, what do you think of

        convert<string, int>(s) & boost::dothrow;

instead of

        convert<string, int>(s) >> boost::throw_t();

People seem to get put off by op>>.

Best,
V.


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