Boost logo

Boost :

Subject: Re: [boost] [TTI] Review for The Type Traits Introspection library by Edward Diener **extended**
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2011-07-18 22:27:46


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.

> 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.

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.

[...]

- Jeff


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