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-19 09:23:16


On 7/18/2011 10:27 PM, Jeffrey Lee Hellrung, Jr. wrote:
> On Mon, Jul 18, 2011 at 5:26 PM, Edward Diener<eldiener_at_[hidden]>wrote:
>
>> On 7/17/2011 11:35 PM, Jeffrey Lee Hellrung, Jr. wrote:
>>
>>> On Sun, Jul 17, 2011 at 6:23 PM, Edward Diener<eldiener_at_[hidden]**
>>>> wrote:
>>>
>>> On 7/17/2011 7:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
>>>>
>>>> [...]
>>>
>>> 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.
>>>>
>>>>
>>> Hmmm..very true, I guess something like that could and will come in handy.
>>> The use case I'm thinking of is
>>>
>>> typedef typename boost::mpl::eval_if<
>>> has_type_value_type<T>,
>>> get_type_value_type<T>,
>>> boost::mpl::identity< some_default_value_type>
>>>
>>>> ::type value_type;
>>>>
>>>
>>> I think one of the things I don't like about the current setup is that
>>> there
>>> are separate HAS_TYPE and MEMBER_TYPE macros, and hence separate
>>> metafunctions, and I'd imagine implementation-wise they largely do the
>>> same
>>> thing.
>>>
>>
>> MPL is very clear about not globbing more than one thing as a result of a
>> metafunction. I agree with this.
>>
>
> :: nod ::
>
>
>> I also don't think the *name* MEMBER_TYPE / member_type_xxx really conveys
>>> well what this macro / metafunction combination does; I don't have any
>>> alternatives at the moment.
>>>
>>
> Actually, I'm not finding it so bad anymore. But you might do well putting
> it into its own separate section in the documentation.

It is documented separately from the HAS_ macro metafunctions and from
their equivalent nullary type metafunctions.

>
>
>> This might not be a good idea, but maybe it could lead a better
>>> alternative. What if we added a nested template get to has_type_xxx that
>>> was a unary metafunction? The semantics could be
>>>
>>> has_type_xxx<T>::template get<>::type => equivalent to T::xxx (and
>>> errors
>>> if a nested type with no such name exists)
>>> has_type_xxx<T>::template get<U>::type => if T has a nested type named
>>> xxx, evaluates to xxx, else evaluates to U
>>>
>>
>> I understand this but I am not enamoured of your syntax. Let me think about
>> it.
>>
>
> Yeah I'm not totally on board either. Another idea is to have a special,
> additional macro generate both metafunctions.
>
> 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.
>>>>
>>>> [...]
>>>
>>> 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.
>>>>
>>>>
>>> That would make 3 or 4 ways (depending on how you count it) to do the same
>>> thing (deeply nested type introspection):
>>>
>>> 1) the solution described in "Nested Types" using (only) MEMBER_TYPE /
>>> member_type_xxx;
>>> 2) the solution described in "Using Nullary Type Metafunctions" using TTI
>>> metafunctions;
>>> 3) the solution described in "Using Nullary Type Metafunctions" using TTI
>>> metafunction classes; and
>>> 4) the proposed new solution using Boost.MPL lambda expression predicates
>>> within the has_type_xxx queries.
>>>
>>> I think, as a general rule, if you have 3 or 4 ways to do the same thing,
>>> you're asking for confusion.
>>>
>>
>> We have a different philosophy about this.
>>
>> First of all there are really three solutions, with your suggestion added
>> to the two I already had. Your 2) and 3) above are hardly 'different".
>>
>
> Like I said, it depends on how you count. They're as different as the the
> metafunctions and metafunction classes are different. It's moot anyway if
> you're dropping the metafunction classes in favor of boost::mpl::quote[n].
>
> Secondly MEMBER_TYPE can be used in any scenario where a nested type has to
>> be passed in a TTI metafunction where it may not exist. This includes as a
>> type in member function and member data expressions in TTI. I do hear you
>> when you say you want HAS_TYPE to also serve the purpose which MEMBER_TYPE
>> has now so as not to have to duplicate HAS_TYPE and MEMBER_TYPE
>> functionality.
>>
>
> Yeah but I'm starting to believe this duplication is inevitable.
>
>
>> Thirdly I do not really see where the "one way is the only right way" is
>> best here.
>>
>
> I'm not saying, in general, that if there are 3 (or 4) ways to do the same
> thing, that one necessarily has to be the best and right way. Indeed,
> solution (1) is naturally possible with anything remotely like
> member_type_xxx, and solution (4) is naturally possible assuming
> has_type_xxx accepts Boost.MPL lambda expressions. Really the only argument
> I can make for (4) over (1) is it arguably has a more natural nesting order
> and it doesn't require any additional constructs beyond has_ queries.
>
> As for (2) (say)...I think I would be more accepting of it there was just
> *one* generic component that wrapped metafunctions into nullary type
> metafunctions, rather than 10 as there are currently, and framed the use of
> nullary type metafunctions (i.e., fully lazy MPL) in a more general
> context. By itself, I don't see the value it provides. Specifically, I'm
> missing...
>
> Finally, My previous two techniques, macro metafunctions and nullary type
>> metafunctions, are generalized ways to use TTI where the latter is merely a
>> syntactical improvement over the former for people like me who don't like to
>> have to grab the nested "::type" in metaprogramming constructs all the time.
>
>
> ...this :( You're trading "typename ... ::type" (and these are only
> necessary in the deeper levels of the query for solution (4) above, if you
> want) for mf_member_type and mf_has_whatever. See my previous email
> comparing the syntaxes of the various approaches (which, I admit, may have
> been unfair as I'm not sure if I got the other solutions right...I *think* I
> did, though). This trade does not seem to be an improvement, at least not
> syntactically. If you can convince me otherwise, I think, at a minimum, it
> will help the documentation. Side-by-side comparisons would certainly help.
>
> Speaking of which, no matter how many techniques you present to perform
> deeply nested type introspection (or any other task), it's important to
> convey to the user the pros and cons of each technique, so that they can
> make an informed decision. Just to reiterate, I don't feel like you've made
> your case (after reading the documentation) that the nullary type
> metafunctions are a syntactic improvement, which is their raison d'etre
> according to the documentation.

I will think about simplifying and leaving out the nullary type
metafunction syntax. Evidently they have caused consternation not only
to you but others as something that is muddying the waters of what
should be a basic set of functionality. In the docs, when I mentioned
them, I thought I had separated them and emphasized their purely
"syntactical" difference enough so that they could be skipped over by
others who felt that they were not useful enough to bother with. They
are not meant to be "lazy" and I did not think they would be any
"slower" compile-time wise than normal metafunction syntax where one
passes types around through the nested ::type member, as Dave Abrahams
suggested they might be.

Why they appear more convenient to me is just a personal matter. I can
only liken it to how syntactically neat it is that boost::mpl passes
around metafunctions rather than their underlying types or values when
doing type selection and computations. I just find that passing
metafunctions until one wants a final result ( whether ::type or ::value
) rather than passing the nested ::type or ::value a more pleasant syntax.

So be it. I can obviously keep the nullary metafunction syntax purely
for my own personal use of TTI and remove them from TTI. If I ever hear
of anybody asking why their is no way of dealing with metafunctions
directly when working with types in TTI I will just laugh and realize
that whatever one does in programming it is impossible to please
everybody. I am surprised, that given the nature of C++ as a
multi-paradigm language, that there appear to be so many C++ programmers
who get either confused or bothered if one presents more than one way of
doing things in a C++ library. As long as documentation is clear I have
never found that to be a problem when I design software.

>
> Obviously the macor metafunctions are not going to go away as they are the
>> core of TTI. If nobody wants to use the nullary metafunctions except me that
>> is fine but I see no harm in keeping them in the library
>>
>
> I think (hypothetically) if you're the only one who wants to use a component
> of your library (or of any library), generally either (a) whatever
> documentation on the component is not doing a good job conveying its
> purpose, and/or only you know how to really use it; (b) you should be using
> something else (i.e., everyone else has it right); or (c) your needs are
> (highly?) specialized. In cases (b) and (c), I think I have to seriously
> question whether the component is appropriate for Boost. In case (a), it's
> at least not ready for Boost.

Eddie


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