Boost logo

Boost :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2005-07-09 08:01:53


Rob Stewart wrote:
> From: Tobias Schwinger <tschwinger_at_[hidden]>
>
>>Documentation preview (includes three sections):
>>
>> http://tinyurl.com/dg68y (not yet hyperlinked)
>
> ________________________________
>
>>Overview
>>
>>Boost.FunctionTypes provides functionality to classify, decompose
>>and synthesize function types and other compound types such as
>
> ^^^ ^^^
> A prime example of why one really should always use the extra
> comma in a series. There can be no confusion when you do so.
>
> ...classify, decompose, and synthesize function types and
> other....
>

OK.

>
>>pointer-, reference- and pointer to member function types.
>
>
> I don't get what "pointer-" and "reference-" are supposed to be
> joined with to make that phrase work. There are function
> pointer types and function reference types, but there are no
> "pointer-function types" or "reference-function types."
>

OK.

> I'm assuming you meant this:
>
> ...types such as function pointer, function reference, and
> member function pointer types.
>
>
>>This means in other words to
>
>
> This means you can
>
> > * test whether a type is a specific callable builtin type,
>
> ...specific, callable, built-in type;
>
> Note the trailing semicolon. Since some items in your list have
> commas, you need to use semicolons to separate the list items.

For all of them or just for the one with the commas?

>
> Note also that "builtin" should be "built-in."
>
> > * inspect function properties such as arity, kind, result- and parameter types, and
>
> You haven't defined "kind," so it's not helpful here.

Right. It's an artefact.

> What's "result-" supposed to connect to?

'types', however it seems English lacks this feature to enumerate compound words
with a common ending ;-).

>
> * inspect function properties such as arity, result type,
> parameter types, etc.; and
>
> > * create callable builtin types from specified function properties.
>
> ...callable, built-in types....
>

OK.

>
>>it specializes in the manifold properties of callable builtin
>>types.
>
>
> As someone else wrote, "manifold properties" is almost
> inscrutable to me. While the usage is correct, the word is
> rarely used as an adjective.

Ahh! Now I fully understand what's wrong with this sentence!

>
> s/builtin/built-in/
>
> it specializes in the many properties of callable built-in
> types.

How about

    ... specializes in callable, built-in types.

??

> _____________________________________
>
>>Introduction
>
>
>>About 300 overloads are needed for three different calling
>>conventions and a maximum arity of 10. This calculation is
>
>
> You haven't mentioned "calling conventions" before this.
> Shouldn't that be in the table?
>

It /is/ there. Did you perhaps overlook it in the table?

>
>>simplified and more irregular in reality.
>
>
> s/and more/and is more/
>

OK.

>
>>* it can lead to a noticable slowdown,
>
>
> * can be slower,

Slower than what?

>
> (If not, fix the spelling of "noticeable.")
>

OK. I'll go with this one.

>
>>This is why Boost.FunctionTypes factors it out and allows
>
> ^^
> Missing antecendent.
>

OK.

>
>>client code to arbitrarily classify and decompose any of the
>>type's multi-faceted properties:
>
>
> Boost.FunctionTypes addresses those disadvantages and allows
> your code to arbitrarily classify and decompose any of a
> function type's properties. The example becomes much simpler
> as the function template's template argument list and formal
> parameter type are reduced to "T":
>

The beginning is good. It's still too lengthy for my taste. Btw: simpler than what?

>
>>It can be desirable to transform callable built-in types. This
>
>
> In other situations, you may need to transform from one
> callable built-in type to another.
>

I try to avoid 2nd person singular except for "please note blocks."

    Another situation is to ...

Isn't that "from one to another"-thing implied by "tranform?"

>
>>is especially useful together with Boost.Function. The next
>>example shows specializing boost::function to store an
>>arbitrary callable scalar f of type F.
>
>
> This example illustrates how to specialize boost::function to
> store an arbitrary, callable scalar f of type F:
>

Nice!

> The example for that should really build upon the previous
> example:
>
> template<typename F>
> void facility::register_function(F f)
> {
> boost::function<typename function_type<F>::type> wrapped = f;
> // call wrapped as appropriate
> }
>

It's intentional because it makes little sense in this context: You'ld usually
want to do declare the boost::function at class scope (of a different class).
More details on this issue can be found below.

>
>>An opportunity for optimization is to transform the signature
>>changing by-value parameters to use constant references to
>>avoid duplicate copy-construction when the boost::function
>>object's parentheses operator is called (the fact that adding a
>>reference can be inefficient for small sized objects is ignored
>>for the sake of simplicity here).
>
>
> Too long and missing at least a comma. It also doesn't guide the
> reader enough.
>
> A common optimization, when forwarding parameters from one
> function to another, is to transform by-value parameters to
> references to const. This avoids creating superfluous copies
> when one function calls another.

Great!

>
> In our example, if register_function() takes the argument types
> from its template argument F and uses them to declare the
> boost::function object f. If F includes by-value parameters,
> then register_function() will create superfluous copies of its
> arguments when calling f. Ideally, we want f to take its
> arguments by reference to const to avoid those copies. (For
> simplicity's sake, we ignore the fact that passing by-value is
> more efficient for small objects.)
>
> Unfortunately, optimized_prototype doesn't help one understand
> how this technique applies to register_function().

OK. I had an invocation for this metafunction in there once... Seems it accidently
got cut away ;-(.

> As you can now see, I think you should develop register_function() as you go
> along so the reader can see the reason for each aspect for which
> Boost.FunctionTypes can offer help.
>

As stated above it's not that easy and would require more infrastructure around
the examples.

Previous example:

     template<typename T>
     void facility::register_function(T a)
     {
  < // [...] <-- use Boost.FunctionTypes on T
> BOOST_MPL_ASSERT_MSG(is_callable_scalar<T>::value
> ,NO_CALLABLE_SCALAR_TYPE, (T));
> this->callback = action<T>(a); // <-- uses Boost.FunctionTypes on T
     }

Then:

     template<typename F> class action
     {
       boost::function<typename function_type<F>::type> wrapped;

       action(F f)
         : wrapped(f)
       // ...
     };

Well, what I don't like about it (besides that there's more infrastructure around
the actual thing) is that both are not necessarily the same case. I'm not feeling
too strong about it, though (at least when there are headlines for every use case).

>
>>When taking the address of an overloaded function or function
>>template, the type of the function must be told to the
>>compiler.
>
>
> This part seems abrubtly different from the preceding text and
> examples. Does it fit with register_function() somehow or is it
> unrelated?

Actually, all three are different.

> If the latter, might I suggest that you delineate
> that separation?

I'ld have to add a headline for all of them (I wanted to do so but failed finding
good titles so I left it out, for now).

> IOW, develop register_function() as far as you
> can using Boost.FunctionTypes facilities. When that example runs
> dry, move on to a new section and discuss the other facilities of
> the library with new examples.
>
> "Must be told to the compiler" is awkward at best.
>
> ...you must give the function's type to the compiler.
>

OK.

>
>>Boost.FunctionTypes can help automating it.
>
>
> Fortunately, Boost.FunctionTypes can help to automate those
> cases:
>

Not sure about the "fortunately" -- the rest of it is bought.

>
>>The above metafunction can be used to create a situation
>>similar to the third trivial example above in a nondeduced
>>context of a function template like the following.
>
>
> function_pointer_helper can now be used to simplify
> <something>....
>

Good.

> "The third trivial example above in a nondeduced context of a
> function template" is practically useless. One has to work so
> hard to grok that phrase that one is unlikely to do it, so the
> example isn't likely to be of much value.
>
> What would be useful is to show exactly how to solve the
> std::for_each example.

The problem is that you won't need the library for the std::for_each example.

> Don't leave more than necessary as an
> exercise for the reader. This is the introduction and you want
> to show how your library is actually used to solve real problems.
>
> feed_tuple_to_function references "Fusion" tuples. I presume
> those are part of the project under development for Boost that
> has yet to be accepted (so far as I recall). Why introduce what
> is likely to be foreign to many readers in your introduction?

It's a sub library of Boost.Spirit since Boost 1.31 (Fusion as a stand-alone
library has yet to accepted, though).

You don't have to be too familiar with Fusion to understand what's happening here.

>
>
>>Assuming these delcarations;
>
>
> s/delcarations;/declarations/
>
>
>>Note that this technique is generally not well-suited to serve
>>as an interface for generic facilities because it has many
>>limitations, such as requiring a known result type and the
>>exact parameter types (rather than types for possible
>>arguments) and because feed_tuple_to_function cannot be
>>overloaded.
>
>
> After looking at the example and reading that text, I'm left to
> wonder what value the example offers.

Not everything has to be entirely generic to make sense and not every technique
out there is for creating interfaces of generic libraries...

> Is it something a person needs to do with any regularity (something I'd expect from a
> library introduction)?

There's not much regularity in the exact case shown by the example. However
overload selection (the principle behind the example) is an important use case and
should be shown here.
Testing whether a class type contains a particular member function (based on
SFINAE and sizeof), is a more regular case but less obvious and depends on tricky
techniques that would require off-scope explanation.

Thank you very much,

Tobias


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