Boost logo

Boost :

Subject: Re: [boost] [TTI] Review for The Type Traits Introspection library by Edward Diener **extended**
From: Edward Diener (eldiener_at_[hidden])
Date: 2011-07-17 21:23:45


On 7/17/2011 7:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
> On Sun, Jul 17, 2011 at 2:49 PM, Edward Diener<eldiener_at_[hidden]>wrote:
>
>> On 7/17/2011 3:21 PM, Jeffrey Lee Hellrung, Jr. wrote:
>>
> [...]
>
>> The light went on finally. You want the 'type with check' idea to be
>> extended to any check which can be formulated in terms of a metafunction
>> rather than just a check that a typedef is the same as some other type.
>>
>
> Yep.
>
>
>> That is a fruitful idea but I really have to think about that in terms of
>> the syntax I have already developed. I am not saying it can not fit in to my
>> current design, even most successfully.
>>
>
> I don't think it changes any syntax other than advanced usage of
> has_type_xxx and eliminating the need (from what I've seen so far, anyway)
> of BOOST_TTI_MEMBER_TYPE, boost::tti::valid_member_type, and the nullary
> type metafunction framework.
>
>
>> struct T
>>> {
>>> struct A
>>> {
>>> struct B
>>> {
>>> struct C
>>> {
>>> int x;
>>> };
>>> };
>>> };
>>> };
>>>
>>> Question: Does the type T::A::B exist?
>>>
>>> Answer:
>>> BOOST_TTI_HAS_TYPE( A )
>>> BOOST_TTI_HAS_TYPE( B )
>>> using boost::mpl::_1;
>>> has_type_A< T, has_type_B< _1> >::value
>>>
>>
> Let's contrast the above with the solutions presently in the documentation:
>
> // Using MEMBER_TYPE
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_HAS_TYPE( B )
> has_type_B< typename member_type_A<T>::type>::value
>
> // Using nullary type metafunctions
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_HAS_TYPE( B )
> using boost::mpl::_1;
> using boost::mpl::identity;
> mf_has_type<
> has_type_B< _1>,
> mf_member_type<
> member_type_A< _1>,
> identity<T>
> >
>> ::value
>
> Did I get those right? I'm not sure :(
>
> Question: Does the type T::A::B::C exist?
>>>
>>> Answer:
>>> BOOST_TTI_HAS_TYPE( C )
>>> using boost::mpl::lambda;
>>> has_type_A<
>>> T,
>>> has_type_B<
>>> _1,
>>> typename lambda< has_type_C< _1> >::type
>>> >
>>>
>>>> ::value
>>>>
>>>
> Again, let's contrast the above with the solutions presently in the
> documentation.
>
> // Using MEMBER_TYPE
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_MEMBER_TYPE( B )
> BOOST_TTI_HAS_TYPE( C )
> has_type_C<
> typename member_type_B<
> typename member_type_A<T>::type
> >::type
>> ::value
>
> // Using nullary type metafunctions
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_MEMBER_TYPE( B )
> BOOST_TTI_HAS_TYPE( C )
> using boost::mpl::_1;
> using boost::mpl::identity;
> mf_has_type<
> has_type_C< _1>,
> mf_member_type<
> member_type_B< _1>,
> mf_member_type<
> member_type_A< _1>,
> identity<T>
> >
> >
>> ::value
>
>
>> Question: Does the type T::A::B::C exist and have a member data x of type
>>> int?
>>>
>>> Answer:
>>> BOOST_TTI_HAS_MEMBER_DATA( x )
>>> has_type_A<
>>> T,
>>> has_type_B<
>>> _1,
>>> typename lambda< has_type_C<
>>> _1,
>>> typename lambda< has_member_data_x< _1, int> >::type
>>> > >::type
>>> >
>>>
>>>> ::value
>>>>
>>>
> Last example.
>
> // Using MEMBER_TYPE
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_MEMBER_TYPE( B )
> BOOST_TTI_MEMBER_TYPE( C )
> BOOST_TTI_HAS_MEMBER_DATA( x )
> has_member_data_x<
> typename member_type_C<
> typename member_type_B<
> typename member_type_A<T>::type
> >::type
> >::type,
> int
>> ::value
>
> // Using nullary type metafunctions
> BOOST_TTI_MEMBER_TYPE( A )
> BOOST_TTI_MEMBER_TYPE( B )
> BOOST_TTI_MEMBER_TYPE( C )
> BOOST_TTI_HAS_MEMBER_DATA( x )
> using boost::mpl::_1;
> using boost::mpl::identity;
> mf_has_member_data<
> has_member_data_x< _1>,
> mf_member_type<
> member_type_C< _1>,
> mf_member_type<
> member_type_B< _1>,
> mf_member_type<
> member_type_A< _1>,
> identity<T>
> >
> >
> >
>> ::value
>
> I might be biased, but I see several advantages to my proposed solutions:
> (a) Proposed solution: write the query from the top down; present solutions:
> write the query from the bottom up.

That is a nice feature.

> (b) Proposed solution: reuse existing metafunction generation framework, no
> need to learn additional constructs outside of boost::mpl::lambda (and then
> only for deeply nested queries); present solution: need to learn a number of
> new structures, including MEMBER_TYPE, mf_has_*, and mf_member_type.

I think you are still missing what MEMBER_TYPE is used for in other
contexts. This is when you need to supply a type whose type depends on
some unknown T and is nested to some depth, and the type may or may not
exist. In this case using complicated logic checking on whether or not
HAS_TYPE exists becomes difficult. Now I grant you I may be able to
build a better MEMBER_TYPE based on your idea above, and I will look
into it.

Also despite your feeling that the mullary type metafunctions should go
away they still, in my mind, are valuable as an alternate syntax to the
macro metafunctions even with your has_type extension idea.

> (c) Referring to the last example above, the proposed solution actually
> takes about as many non-whitespace characters (I counted 120) as the
> "MEMBER_TYPE" solution (I counted 118) and far fewer than the "nullary type
> metafunction" solution (I didn't bother counting, but it certainly *looks*
> about 50% longer). In the first example, I think the proposed solution is
> clearly the winner in terms of fewest characters. [If only we had de Bruijn
> indices in Boost.MPL...]
>
> FWIW, I had a lot more difficulty figuring out what the right queries were
> in terms of the present syntax than with the proposed syntax, but then I
> consider myself well-versed in Boost.MPL. I think it was actually confusing
> for me that you mixed the metafunction class syntax with the metafunction
> syntax in the "Using the Nullary Type Metafunctions" example :/

I perhaps should not have done that. I was not trying to show off but
just to show that either could be used interchangeably with the same
result. I should have kept it simple and stayed with the placeholder
syntax while mentioning the alternative metafunction class syntax.

> It took me
> a while to convince myself that mtfc_member_type_CType could just as easily
> have been replaced with member_type_CType<_>.

Again my fault of not just explaining my examples better.

>
> Yes, I now understand what you are suggesting with the second template
>> parameter to has_type_xxx. I need to think about this before I answer it
>> fully but I do not want to let it impede what already currently exists as
>> part of the library and the review so my thoughts may take some time once
>> the review ends.
>
>
> It is a significant change to the current interface, I agree, but (of
> course) I believe it is a change in the right direction.
>
>
>> But I will respond eventually. I admit I am not in love with lambda syntax
>> as compared to the nullary type syntax and all those nested ::type and final
>> ::value
>
>
> Well, let's be fair here. The "MEMBER_TYPE" solutions have the typename ...
> ::type constructs as well (I know it's not your preferred solution); the
> nullary type syntax has an extra mf_member_type at each level of the query
> hierarchy; and I just tacked on the final ::value so I was getting a boolean
> expression in the end. Present solutions have that, too.
>
>
>> but certainly drilling down through 'types' in a hierarchy in the order in
>> which they are viewed is an advantage.

I still feel that if I add your idea it will be added as an addition and
not as a complete replacement of anything else. My reasoning is that not
everyone is as knoweldgable about MPL and as comfortable with lambda
expressions as you are.

Eddie


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