|
Boost : |
Subject: Re: [boost] [conversion] ADL and templates
From: Vicente Botet (vicente.botet_at_[hidden])
Date: 2011-06-01 04:24:21
Jeffrey Lee Hellrung, Jr.-2 wrote:
>
> On Tue, May 31, 2011 at 1:06 PM, Vicente Botet
> <vicente.botet_at_[hidden]>wrote:
>
>>
>> Stewart, Robert wrote:
>> >
>> > Vicente Botet wrote:
>> >>
>> >> There is something that is troubling me on the fact that the
>> >> developer will customize the conversion function using
>> >> overload and ADL, but that the user could not take advantage
>> >> in a simple way of this overloading. Taking in account that
>> >> Boost.Conversion needs already a customization point to take
>> >> care of conversion of types in the standard library (using
>> >> partial specialization) the addition of the customization
>> >> point using overload doesn't make simpler the user code,
>> >> neither the developers customizing the class, as it would
>> >> need to choose between two customization points that doesn't
>> >> make any difference.
>> >>
>> >> If no one find that the additional customization (via
>> >> overloading) point add some benefit to the library, I will
>> >> prefer to remove it. This will have the advantage of making
>> >> the library quite more simple without limiting his
>> >> expression power.
>> >
>> > I have no idea to what you're referring. I've long since lost any
>> notion
>> > of what overloads, customization points, etc. you're discussing. Can
>> you
>> > show, with code, what the choices are and what problems you're
>> addressing?
>> >
>> >
>>
>> Hi,
>>
>> sorry I didn't give enough information.
>>
>
> Yes, thanks for this, I was wondering myself as well :)
>
> Currently Boost.Conversion has two customization points:
>>
>> A- overloading of conversion::convert_to function
>>
>> template (*typename Target, typename Source*)
>> Target convert_to(
>> Source const& from,
>> dummy::base_tag<Target> const& p=dummy::base_tag(*Target*)());
>>
>> The dummy parameter is there to allows overloading on the return type.
>>
>
> This signature of convert_to is *not* the signature that
> conversion::convert_to uses, right? I assume this is just the signature
> of
> the customization point.
>
> Also, is there a need for the second parameter to be defaulted?
>
You are right. The preceding was the signature of the convert_to function.
The customization point uses instead a more specific type type_tag, which
derives from base_tag.
template (*typename Target, typename Source*)
Target convert_to(
Source const& from,
dummy::type_tag<Target> const& p);
This as you know is needed to avoid infinite recursion, when the
boost::conversion is is introduced via a using statement.
This is the kind of complexity I want to avoid.
> B- partial specialization of conversion::overload_workaround::convert_to
>> struct.
>>
>> namespace overload_workaround {
>> template (* typename To, typename From, class Enable = void *)
>> struct convert_to {
>> static To apply(const From& val);
>> };
>>
>> The default implementation of conversion::convert_to calls to an internal
>> function that calls to convert_to (ADL) after introducing a default
>> implementation (via using). If the user has defined an overload that is
>> preferred to the default one, his overload is called. If there is no
>> better
>> overload the default one call the
>> conversion::overload_workaround::convert_to::apply function, which by
>> default returns Target(from).
>>
>> The partial specialization part is needed as we can not add overload on
>> the
>> std namespace.
>>
>
> Fair enough.
>
>> When I introduced this complex mechanism I was expecting that the user
>> could
>> call the convert_to function without using the boost::conversion
>> namesapce,
>> but this is only true if it uses explicitly the dummy parameter, which
>> doesn't seems natural to me.
>>
>
> I'm confused. You want the user to be able to call their own
> customization
> function directly without the use of a dummy parameter, by-passing
> boost::conversion::convert_to? I'm not sure I see the point...
>
It would need to use the dummy parameter.
convert_to(v,boost::conversion::type_tag(*T*)());
> So if the user needs always to call the conversion function as follows
>>
>> boost::conversion::convert_to(*T*)(v)
>>
>
> I don't see what's wrong with that...
>
>> Now, I don't see any advantages to maintain the customization point (A).
>>
>
> Well, (A) puts the customization within the user's namespace, while (B)
> requires opening the overload_workaround (or whatever) namespace. (A)
> only
> requires defining a function, while (B) requires specializing a struct and
> defining a member function. They both seem to achieve the same affect,
> but
> from the user's POV, (A) seems simpler.
>
Maybe it is simple once the user has understood the mechanism, but the
mechanism is more complex.
> The customization point B alone allows to make whatever can be done with
>> both and it simplifies quite a lot the implementation.
>
>
> "quite a lot" seems like a bit of an overstatement, although maybe you're
> speaking relative to the library as a whole. How much code accounts for
> the
> difference between allowing (A) and removing (A) altogether?
>
Really, not too much. But makes the customization point from been simple to
been quite complex.
If we take in account some of the other functions like assign_to,
try_convert_to, convert_or_fallback, should these functions be customizable?
>> The default
>> conversion::convert_to function needs just to call the customization
>> point
>> B.
>>
>
> Correct. The only thing (A) offers is (maybe) simplicity over (B).
>
>> I suspect that after refactoring, I will rename the namespace
>> overload_workaround by something more positive. Any suggestions?
>>
>
> Or you could rename the convert_to struct to something else. Perhaps you
> should look in other Boost libraries to see how customization points are
> structured (Boost.MPL, Boost.Fusion, Boost.Spirit, and possibly
> Boost.Phoenix come to mind).
>
I will do.
>> If you need more details of the current implementation, you can take a
>> look
>> at the header
>>
>> http://svn.boost.org/svn/boost/sandbox/conversion/boost/conversion/convert_to.hpp
>> .
>>
>> Hopping this would be clear for you now.
>>
>> Thanks for your interest,
>> Vicente
>>
>> P.S. Sorry again for the angle brackets (* *)
>>
>
> One thing I wonder is: Suppose we have two classes from two different
> libraries, TypeA from LibraryA and TypeB from LibraryB, and we wish to
> define a conversion operation from TypeA to TypeB via Boost.Conversion.
> Does Boost.Conversion specify which library should contain this operation?
> I would suspect it couldn't, which makes me think there should be 2 levels
> of customization. For example, the first level of customization is
> defined
> by LibraryX when TypeX is the From type, and the second level of
> customization is defined by LibraryX when TypeX is the To type (X = A or
> B). Thus, if LibraryA provides a customization to convert TypeA to TypeB,
> but LibraryB likewise provides a customization to convert TypeA to TypeB,
> the customization in LibraryA is used unambiguously.
>
> - Jeff
>
This is the major problem these conversion functions could introduce and
maybe the reason the standard doesn't allows the free function conversion
operator and assignment operator. We can find two pieces of source code
customizing the same conversion.
But this is a more general problem. Think for example to the binary
operator+(). This operator can be overloaded by two libraries with the same
LHS and RHS types, and the program will be ill formed. Which library should
provide the overloading? I have no response to this.
The major advantage of having a single customization point is that the
compiler can detect the ambiguity.
The major problem of a single customization point in case of conflict, is
that the single way to avoid the conflict is to be able to don't include one
of the definitions.
Your two levels proposition don't work always as it suppose that the
conversion between TypeA and TypeB will be done either by libraryA or
libraryB. The common case is that it will be libraryC which will include the
conversion as if a conversion between TypeA and TypeB doesn't exists is
because they don't know each other. So the problem is moved to how libraryC
and libraryD use these customization points.
Best,
Vicente
-- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p3565232.html Sent from the Boost - Dev mailing list archive at Nabble.com.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk