Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2005-07-01 14:16:31


Tobias Schwinger <tschwinger_at_[hidden]> writes:

> Hi Dave,
>
>
> David Abrahams wrote:
>> Tobias Schwinger <tschwinger_at_[hidden]> writes:
>>
>
>>
>> Let's try this again:
>
> Thanks for your rewrite. I hope it gives us a starting point to finally straighten
> this section, which seems quite tricky to document and I really can use any help
> with it!
>
>>
>> Tag Types
>> ----------
>>
>> The Function Types library uses *tag* types to represent or query one or
>> more properties of a type, such as its variadicness, or whether it is
>> a pointer.
>>
>
> The "kind" term from the previos version was meant to be defined in a more global
> place. Like this:
>
> A type supported by this library is completely described by its
> subtypes

Subtypes? I think you mean argument, optional class target, and
return types. These are not (necessarily) "subtypes!" That word has
a very specific -- and different -- meaning in computer science.

> and its kind. The kind collectively refers to the following information:
> - decoration (none,pointer,reference,member pointer)
> - variadicity
> - cv-qualification of member function pointers
> - the calling convention attribute
>
> Actually it is very helpful - not only for this part. Maybe reintroduce it?

It may be helpful somewhere, but "kind" is absolutely and utterly
unnecessary for understanding the section I've rewritten here.
Introducing it into these sentences just complicate them.

     A type supported by this library is completely described by its
     argument types, return type, class target (if the type is a
     member pointer), and the following properties:

     - decoration (none,pointer,reference,member pointer)
     - variadicity
     - cv-qualification of member function pointers
     - calling convention

You really don't intend to represent cv-qualification of member
function pointers as simply the cv-qualification attached to the class
type?

>> Tags that represent the values of a single property are called
>> *property tags*. These tags can be used to determine whether one
>> property of the type has a particular value.
>>
>> is_function< T, variadic >
>> is_function< T, pointer > // same as is_function_pointer<T>
>>
>> To match against several values of a property at once, you can use
>> wildcard property tags:
>
> "Wildcard" requires the context of classification to fit perfectly...

I have no clue what you mean.

>>
>> is_function< T, free_or_static >
>>
>> // the tag 'free_or_static' captures two values of the decoration
>> // property and makes the above code equivalent to:
>>
>> mpl::or_< is_function_type< T, undecorated>
>> , is_function_type< T, pointer >
>> , is_function_type< T, reference > >
>>
>> [?? This example doesn't make any sense to me; what do "undecorated,"
>> "pointer," and "reference" have to do with whether a function is free
>> or static?? If you really meant what you wrote, you had better
>> explain -- at length!]
>
> The very first sentence descibing the library in a whole introduces it (this has
> not been posted yet). I'm not sure it is sufficient, though:
>
> Overview
>
> This library provides functionality to classify, decompose and synthesize
> function types and other compound types directly decorating a function type
> with a pointer, reference or member pointer.
>
> So the idea behind the decoration property is this:
>
> Given a function type F
>
> F is undecorated \
> F* is pointer decorated - free or static decoration ("wildcard")
> F& is reference decorated /
> C::*F is member-pointer-decorated
>
> The reference shows this grouping, too. Unfortunately the "[/ FIXME: add link to
> reference ]" at the point where the "aspect tags" are introduced got lost (because
> I copied from the browser instead of my .qbk master file).

Okay, I understand. That said, the way you are classifying these
things is going to cause confusion. There is no distinction between
the types of static member functions and the types of free functions.
There is only a distinction in how they are declared; once you are
dealing with their types, they are the same thing. The name
"free_or_static" carries the implication that you have precise
(non-wildcard) tags "free" and "static". In my opinion, you should
use the terms "member" and "nonmember." A pointer to a static member
function is not a member pointer in the C++ type system; that's why my
suggested terminology works. So "free_or_static" should be "nonmember."

>> Every property has a fully-general wildcard tag that can be used to indicate
>> that /any/ value of the property should be matched. The tag's name is the
>> same as that of the property, but with the prefix "unspecfied_".
>>
>> is_function< T, unspecified_decoration >::value
>> // true for any type T that the library can handle
>>
>> [You need to say more clearly what "can handle" means. IMO the
>> comment should really be expressed as the last sentence of the
>> foregoing paragraph]
>
> s/type the library can handle/(possibly decorated) function type/

"(possibly decorated)" adds nothing. You have already made it clear
that function types can be decorated -- or if you haven't, you can't
just throw the term in here in parentheses and expect anyone to
understand what you mean.

>>>Each abstract variation of an aspect has a non-abstract semantic
>>>equivalence
>>
>>
>> Wha??? I don't know how to translate that into something simpler,
>> because I can't tell what it means!
>>
>
> It means that wildcards in fact are abstract ;-) and undergo a process of
> "automatic concretization" in the context of type synthesis.

Wha??? I can't tell what that means either.

> This does not directly give us a use case

I don't understand what you mean by that either.

> but is essential to understaning the
> logic because it allows us to write:
>
> function_type< mpl::vector<int,int>, pointer >::type
>
> What happens here is: all properties other than the decoration property default to
> unspecified_*.

Why does the user care what happens under the covers?

> These are "concretized" (in this context -- we need a concrete
> description for creating a type) to produce a pointer to a
> non-variadic function of the default calling convention.

Why make this so complicated? Just say that properties for which no
value is specified acquire a default value, and show an example!

> Because of this "concretization", the same tag expressions work for both
> classification and synthesis:
>
> is_function<F,pointer>::value
>
> Here ^^^ we ignore anything except the decoration property.

That point may be interesting to you, but AFAICT it doesn't help a
user in any way.

>>>when used in the context of type synthesis (as defined
>>>in the reference section).
>>>
>>> function_type<void(X::*)(), free_or_static>::type
>>>
>>> // is equivalent to:
>>>
>>> function_type<void(X::*)(), undecorated>::type
>>
>>
>> And the example doesn't help me tell what it means, mostly because of
>> my confusion above, probably.
>>
>
> As I said: it does not directly give a use case. So the "examples" are in fact
> "demonstrations of behaviour" fundamental to the logic.

I don't understand what you're saying there either.

>>>A tag created from a type completely describes all aspects of the type's kind. The
>>>aspect variations in the tag are never abstract.
>>>
>>> signature< void() >
>>> // describes all aspects: undecorated, non-variadic, ...
>>
>>
>> A signature tag is a compound tag that precisely describes all of
>> a specific type's properties, so it does not act as a wildcard.
>>
>> signature< void() >
>> // describes all aspects: undecorated, non-variadic, ...
>>
>> [This example fails to illustrate your main point, which is that it
>> doesn't act as a wildcard. That said, I'm not sure it's an important
>> point to make -- it should be obvious! Anyway, if you use this
>> section it should come after compound property tags are introduced below]
>
> Agreed. I wasn't to happy about its placement either.
>
> By the way:
>
> signature<F>
> // is model of: Tag & Front-/Back Extensible/Random Access MPL Sequence

I figured as much.

>>>When classifying and especially when synthesising types, there are situations in
>>>which it is neccessary to describe more than one aspect. Therefore tags can be
>>>combined using the tag metafunction.
>>>
>>> function_type< mpl::vector<int,int>, tag<pointer,variadic> >::type
>>> // is int(*)(int...)
>>
>>
>> [That "tag" template is not obviously a metafunction from its usage.
>> I believe calling it that here (even if it really is one) is
>> confusing. ]
>
> OK. In fact I plan to document a Tag concept.
>
>>
>> A compound property tag describes a combination of possible values
>> of different properties. The tag class template can be used to
>> create a specific compound property tag. The specialization of tag
>> used below matches all pointers to variadic functions, and the type
>> vector further restricts the type matched to int(*)(int,...).
>>
>
> Hmm... I'm having difficulties combining this ^^ text with this VV example.
>
>> function_type< mpl::vector<int,int>, tag<pointer,variadic> >::type
> ^^ this creates a function pointer, not a tag
>
> The example was not sufficiently documented, I guess. Sorry!!!

Ah sorry, no I was just in a hurry. Make the final sentence of the paragraph:

   The specialization of tag used below indicates that the resulting
   function type should be a pointer to a variadic function.

>>>In the context of classification all aspects represented by the
>>>query tag must match:
>>
>>
>>
>> A compound property tag matches a type only when all of its
>> component properties match:
>>
>
> It's not restricted to matching types. It's also possible to match other tags.
> That's why I used the words I did. However, inserting "or another tag" does fix
> it, I believe.

Okay.

>>> is_function_type< void(...), tag<free_or_static,variadic> >::value
>>> // is true
>>>
>>> is_function_type< void(X::*)(...), tag<free_or_static,variadic> >::value
>>> // is false
>>>
>>>Except for tag combination, each aspect that is not represented by a tag is
>>>similar to the abstract variation represented by the tag named "unspecified_" plus
>>>that aspect's name. This is why these tags do not have to be specified in many
>>>contexts.
>>
>>
>> [I don't know what "except for tag combination" is supposed to mean
>> above, so I left it out below, but if it's important, you need to
>> describe what _does_ happen when you use the fully-general wildcard in
>> a "tag combination" (whatever that is)]
>
> "Tag combination" was supposed to mean: "tag<T1,T2>".
>
> What does happen is what happens for all properties described in the
> next paragraph.
>
>>
>> The fully-general wildcard tag for any property not otherwise
>> represented can be added to a tag specialization without changing
>> its meaning.
>>
>
> It's not entirely true (and what I was trying to say), because:
>
> typedef tag< variadic, unspecified_decoration > X;
> typedef variadic Y;
>
> tag< pointer /* <-- gets overridden */ , X >
> tag< pointer /* <-- does not get overridden */ , Y >

That's why I said "not otherwise represented." I believe the
statement is true.

> So X and Y have different meanings but it won't matter unless they
> are used to (explicitly or implicitly) form another compound tag.

That may be a further interesting point to make, but I believe you
should cover the topic of doubly-compound tags in a separate section,
if at all.

>> When several tags for the same property appear in the argument
>> list, only the last one is used; others are ignored.
>>
>> [I assume we are still on the topic of the "tag" class template here,
>> so "the argument list" is sufficient. I wonder if there's a rationale
>> for this behavior, as opposed to making it a compile-time error?]
>
> Oh yes. Try these:
>
> // a remove constness (of the pointee) from a member function pointer type T
> function_type<T, non_const >::type
>
> or
>
> // create a (possibly decorated) function type's variadic version
> function_type<T, variadic >::type
>
> or
>
> // Member function pointer -> function with default calling convention
> function_type<T, tag<undecorated,unspecified_call> >::type

Oh, wait. This use of "unspecified" is very bad, because it conflicts
with the very specific way the C++ standard (and many Boost libraries
as a result) use the word. The calling convention of the result isn't
unspecified -- that would mean "it will be something whose properties
we might describe but we're not going to tell you exactly what it is."
In this case the calling convention is very much being specified to be
the default!

For this purpose, the proper name is "default_call."

> Here the properties of the original types are overridden in an implicit tag
> combination with the tag representing the type.
>
> Well, we /could/ only allow it in this very context,

Allow what?

> however, it maybe makes things more complicated to explain (see
> below) and involves more template instantiations - so I'm not sure
> it's really worth it.

I don't know what you're referring to.

>>
>>
>>> tag<free_or_static,reference>
>>> // decoration aspect is 'reference'
>>>
>>> tag<reference,undecorated>
>>> // decoration aspect is 'undecorated'
>>>
>>> tag<undecorated,reference,unspecified_decoration>
>>> // decoration aspect is 'unspecified_decoration'
>>>
>>> tag<undecorated,variadic,pointer>
>>> // two aspects are set: pointer decoration and variadic
>>>
>>>Tag combination occurs either explicitly by using the tag metafunction or
>>>implicitly. Implicit tag combination takes place when using function_type with a
>>>tag or (possibly decorated) function type as its first template
>>>argument.
>>
>>
>> Tags can be combined either explicitly, by using the tag
>> metafunction, or implicitly. Implicit tag combination takes place
>> when function_type is used with a tag or function type as its first
>> template argument. In the example below, any properties of the
>> first argument to function_type not overridden by those in the tag
>> specialization are turned into a tag and implicitly combined with
>> the tag specialization to produce a new function type.
>>
>> [personally I don't believe it's important for users to know that
>> implicit tag combination happens here, and I think saying so just
>> complicates matters. It would be just as useful to say that "any
>> properties represented in the tag specialization override those of the
>> first argument to produce a new function type," and leave it at that.]
>
> No?
>
> function_type< my_mpl_sequence, pointer > // no implicit tag combination
> VVVVV
> function_type< my_function , pointer > // implicit tag combination
> function_type< signature<F> , pointer > // implicit tag combination
> ^^^^^
>
> I believe it is _very_ important to document this behaviour.

Yes, the behavior should be documented, but the way you are describing
it exposes implementation details and complicates understanding. If
you just say that "any properties of the first argument that are not
overridden by the second argument will be properties of the result"
then you don't need to introduce new jargon for "implicit tag
combination."

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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