Boost logo

Boost :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2005-06-13 18:29:01


Hello Dave,

first of all: thank you very, very much for these numerous hints on how to
improve the documentation - especially for taking the time to rewrite several
passages. Amazing work!

Mind if I just "merge" some of this into the next revision?

I'll cut down your post for the reply to highlight the points I want to answer
to -- and add the others to my todo list.

David Abrahams wrote:
>
> [...]
>
> All this stuff goes in namespace boost? I don't think I'm happy about that.
>
>
>> All names are actually defined inside local namespaces. They are
>> injected to the boost namespace via a using directive.
>
>
> Okay, that's a little better. It avoids some ADL problems but still
> brings many special-purpose names into the top-level namespace. Do
> the tag types belong there? Also "local namespace" isn't a
> well-accepted term. How about "sub-namespaces of boost?"
>
> I don't think the synopsis should show them in namespace boost and
> then be amended by a footnote at the bottom that many people might not
> read. At least put a link to the note in the synopsis code.
>

I was not too sure about this myself. I did this because most libraries put
their primary interface into namespace boost.

>
>> template<typename F>
>> struct function_type_arity;
>>
>> template<typename F>
>> struct function_type_result;
>>
>> template<typename F>
>> struct function_type_class;
>>
>> template<typename F, typename I>
>> struct function_type_parameter;
>>
>> template<typename F, long I>
>> struct function_type_parameter_c;
>>
>> template<typename F>
>> struct function_type_parameters;
>
>
> Yowch! I really hate to see a boost.whatever library with names like
>
> whatever_foo
> whatever_bar
> whatever_baz
>
> in it. Isn't this what namespaces are for?

Okay - if we don't put them in namespace boost, we can also use a different
naming for these. I like it, especially because the names are currently too
lengthy for my taste.

>> is_function_type
>>
>> Members
>>
>> value - Static constant of type bool, evaluating to true if T is
>
>
> Uhm, the essential member of any metafunction is ::type, and I don't
> see it listed here. Value doesn't "evaluate to true", it "is true."
>

is_function_type<Tag,T> is an MPL Integral Constant. The type member is the
identity of its specialization and not listed explicity because it's part of the
concept. It won't hurt, I guess.

>> an element of the set of types specified by Tag. Member function
>> pointers may be more const-volatile qualified than specified,
>
>
> Hmm, have you looked carefully at the use cases for this? Member
> functions often have counterintuitive is-a relationships. For
> example, a base class member pointer is-a derived class member
> pointer, but not vice-versa. It's not obvious to me that any is-a
> relationships should hold here. What are the use cases?

I'm thinking about removing cv indication from the tags and cv-qualifying the
class type, instead (see comments in the examples interpreter.hpp : line 99 and
function_closure.hpp : line 120).

>
>
> ---------
>
>
>> Decomposition
>>
>> Six class templates are provided to extract properties of a function
>> type, such as arity, parameter-, class (where appropriate)- and
>> result type.
>
>
> "Six class templates are provided to extract properties of a function
> type, such as arity and the types of the result, parameters, and the
> class targets of member functions."
>
> -------
>
>
>> template<typename T>
>> struct function_type_arity;
>>
>> Template parameters
>>
>> T - The function type to be inspected. T must be a function type as
>> defined at the beginning of this document
>> (is_function_type<no_function,T>::value == false).
>
>
> You shouldn't repeat that verbose description all over the place.
>
> "T - Any function type <link to definition>"
>
> is better and more concise.
>
>
>> Members
>>
>> value - Static constant of type size_t, evaluating to the number
>> of parameters taken by the type of function T describes. The hidden
>> this-parameter of member functions is never counted.
>
>
> That particular behavior does not match the needs of any use cases
> I've seen. I always want to treat the hidden this parameter as the
> function's first parameter (actually as a reference to the class, with
> cv-qualification given by that of the member function itself). What's
> the rationale?

The rationale is that there is no unified call syntax for member function
pointers and non-member/static function pointers, anyway:

Typically we use a cascade of template specializations that does the actual
invocation for different function arities.

Only counting "real" parameters here allows us to build such a cascade for
arities ranging from zero to "OUR_MAX_ARITY_LIMIT" without having to deal with
the two special cases that there are no nullary member functions and that we
need to go up to OUR_ARITY_LIMIT+1 for member function invocations if the
context reference is taken into account.

Think about generating the (hand-written) cascade in

     libs/function_types/example/interpreter.hpp : line 299

with Boost.Preprocessor, for example.

Even if completely binding a function (which I believe is a rather seldom use
case), we still need a distinction between a member and non-member function
pointer which won't go away no matter how we put it.

Further we can still take the size of function_type_signature (well, in this
case the result type is counted as well).

>
> "I - An MPL Integral Constant describing the index of the parameter
> type to be returned. The index of the first parameter is zero."
>
> What about the hidden "this" parameter? I think you know the
> semantics I want, but you don't say what you provide.
>

The same argumentation applies here.
And parameters indices should be consistent with the function arity.

Further it makes client code more expressive.

I guess it's your turn here to prove my design is faulty ;-).
If you can convince me, I'll happily change things, of course.

> [...]
>
> I don't know what you mean by this recommendation. If I have a
> specialization of function_type_signature, how am I supposed to get
> information about it, or use it? Am I supposed to pass it to the
> decomposition metafunctions (I don't think so!)?
>

Use it as an MPL sequence.

I added this recommendation because it led to so much confusion discussing this
with Jody Hagins (and I probably made things worse).

The recommendation refers to using it as a traits bundle: e.g.

     function_type_signature<T>::arity

instead of

     function_type_arity<T>

which should be preferred.

>
>> template<typename Tag, typename Ts>
>> struct function_type;
>
>
> Needs a brief description; maybe all do. Example: "Returns a new
> function type built from a sequence of types."
>
>
>> Template parameters
>>
>> Tag - Tag type specifying the kind of function type to be
>> created. Abstract tag types (ones that describe abstract supersets
>> of types such as any_function) are not allowed with the exception of
>> no_function (see below for effect).
>
>
> "Tag types that describe abstract supersets of types, such as
> any_function, are not allowed with the exception of no_function (see
> below<link>)."
>
>
>> Ts - Model of MPL Forward Sequence of sub types, starting with
>
>
> Drop "Model of"
>
>
>> the result type optionally followed by the class type (if Tag
>> specifies a member function pointer type)
>
>
> That sounds like if Tag specifies a member function pointer you have
> the option to represent the class type. Just drop "optionally" and
> remove the parens.
>
> So here you are using the form I like, where class types are treated
> just like any other (should be a reference, though). Why not do this
> uniformly.
>

See above.

>> followed by the parameter
>> types, if any. If Ts is not a sequence (mpl::is_sequence<T>::value
>> == false), a specialization of function_type_signature for this type
>> is used.
>
>
> This is unintelligible. You already said Ts is required to be a
> sequence. Now you're taking it back? A specialization of

I remember being rather unhappy about this writing it...

> function_type_signature for *which* type is used? Used how?
>

... it needs to be rewritten.

>
>> This may fail if function_type_signature is an incomplete
>> template due to forward-declaration without definition.
>
>
> Why would that ever be the case? Shouldn't your library take care of
> it?
>

Both 'function_type_signature' (which is the backend for all higher-level
inspection components) and function_type need quite a bit of code (and when used
in preprocessing mode a significant ammount of compile time).

That's why I decided to not let one depend upon the other, but to make them plug
into each other when both are defined.

>> . If Tag is no_function,
>> type is identical to Ts if Ts is an MPL Sequence other than a
>> specialization of function_type_signature, in which case an type is
>> an mpl::vector (this is primarily for internal use of the library
>> but, since it may be useful in some situations, there is no reason
>> to hide it from the user).
>
>
> Oh yes there is!! I can't for the life of me understand these
> semantics. Guideline: anything whose specification is too complicated
> to explain easily probably needs to be redesigned.

It used to be a bit more understandable before I removed a rather strange
feature to grab the signature from a class template's parameter list. I will
just remove this as well.

>
> Also, special-case "if" clauses, especially those that test whether
> something matches a concept (like "is_sequence") tend to destroy
> genericity.
>

Would you mind explaining this in some more detail?

> ----
>
>
>> Portability
>>
>> Currently this library does not contain any workarounds for broken
>> compilers. It was successfully tested with Microsoft Visual C++
>> Versions 7.1 to 8.0, Intel Linux Versions 7.0 to 8.1 and GCC Version
>> 3.2 to 4.0. The library is expected to work with compiler using the
>> Edison Design Group frontend other than Intel, although currently
>> there is no proof for this.
>
>
> Okay, I appreciate the desire to avoid broken compiler workarounds.

Okay. The desire to avoid broken compiler workarounds applies especially to the
review version.

I had hoped the review to answer how much portability is required for proper
Boost integration. I definitely plan on extending the list of supported compilers.

> However, many of the libraries in Boost that could use this library do
> support broken compilers, and therefore -- I think -- are not using
> idioms that can readily leverage metafunctions for this purpose. The
> true measure of whether this library should be accepted, IMO, is in
> whether it can be used to eliminate large amounts of code from other
> libs. Can it? The quickest way to a proof-of-concept is to apply it.
>

Good idea!

> Incidentally, I think
> http://lists.boost.org/MailArchives/boost/msg81758.php makes it
> possible to implement almost any trait we previously thought was
> impossible in pre-7.1 Visual C++.

If the folks at Borland don't fix their compiler they should at least add this
as a new bug...

> I'm not ready to accept this library, and I'm not ready to reject it
> either. It has the potential to be extraordinarily useful, but that's
> unproven as far as I'm concerned. I have some substantial complaints
> with the interface, and I have some serious problems iwth the docs as
> you can see (not all of those remarks are trivial grammatical edits!)

Summary:

- proof it by making some boost libraries use it
- change naming
- change docs

I hope (but am not entirely sure) it's all doable within the review period.
Any hints on a preferred prioritization?

Regards,

Tobias


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