[function types] Formal Review begins today.

The Formal Review of the Function Types Library begins today, and runs until 16th June 2005. Author: Tobias Schwinger tschwinger@neoscientists.org Available from the sandbox at: http://boost-sandbox.sourceforge.net/vault/ or the zip file is: http://boost-sandbox.sourceforge.net/vault/index.php?action=downloadfile&filename=function_types.zip&directory=& This library provides a metaprogramming facility to classify, decompose and synthesize function-, function pointer-, function reference- and member function pointer types. For the purpose of this documentation, these types are collectively referred to as function types (this differs from the standard definition and redefines the term from a programmer's perspective to refer to the most common types that involve functions). The classes introduced by this library shall conform to the concepts of the Boost Metaprogramming library (MPL). The Function Types library enables the user to: * test an arbitrary type for being a function type of specified kind, * inspect properties of function types, * view and modify sub types of an encapsulated function type with MPL Sequence operations, and * synthesize function types. This library supports variadic functions and can be configured to support non-default calling conventions. (The following is taken from : http://www.boost.org/more/formal_review_process.htm ) Here are some questions you might want to answer in your review: What is your evaluation of the design? What is your evaluation of the implementation? What is your evaluation of the documentation? What is your evaluation of the potential usefulness of the library? Did you try to use the library? With what compiler? Did you have any problems? How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? Are you knowledgeable about the problem domain? And finally, every review should answer this question: Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. John Maddock (Function Types review manager).

John Maddock wrote:
Available from the sandbox at: http://boost-sandbox.sourceforge.net/vault/ or the zip file is: http://boost-sandbox.sourceforge.net/vault/index.php?action=downloadfile&filename=function_types.zip&directory=&
One small addition: Online documentation: http://tinyurl.com/4fw9n . Regards, Tobias

The library has been updated and the following changes have been made: Library: -------- The "dark corner-feature" to grab the template signature of a class template has been removed, because it is not worth the trouble it can cause. It should not be in the scope of the library, anyway and should be seen as a bug fix. Documentations: --------------- The documentation has been updated to reflect the above change of the library. Several small, in-place fixes have been applied to address some of the shortcomings reported by Jody Hagins. There still is more room for improvement, but the review period is not the best time for radical changes, especially because more reviewer's thoughts could be helpful for this. Examples: --------- An example to demonstrates the customization of callbacks based on a function's input signature has been added. - interpreter.hpp [ http://tinyurl.com/bu5vn ] - interpreter_example.cpp [ http://tinyurl.com/8ryt3 ] The Jamfile in the 'example' directory has been updated to only build the two example use cases. The other examples are still built as a part of the test suit. The other example use case (which is not new) has been renamed from closure_function to function_closure: - function_closure.hpp [ http://tinyurl.com/cd4hm ] - function_closure_example.cpp [ http://tinyurl.com/9ojtj ]

Tobias Schwinger <tschwinger@neoscientists.org> writes:
The library has been updated and the following changes have been made:
You know that the library that's under review needs to remain available and unchanged during the review period, don't you? It's fine to post updates, as long as the original is still accessible through its original URL. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
Tobias Schwinger <tschwinger@neoscientists.org> writes:
The library has been updated and the following changes have been made:
You know that the library that's under review needs to remain available and unchanged during the review period, don't you? It's fine to post updates, as long as the original is still accessible through its original URL.
Maybe this should be stated explicitly. The following quote: "A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list." doesn't make it clear (for me, at least) that the original version has to remain available after a fix has been uploaded. Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote
Tobias Schwinger <tschwinger@neoscientists.org> writes:
The library has been updated and the following changes have been made:
You know that the library that's under review needs to remain available and unchanged during the review period, don't you? It's fine to post updates, as long as the original is still accessible through its original URL.
Maybe this should be stated explicitly. The following quote:
"A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list."
doesn't make it clear (for me, at least) that the original version has to remain available after a fix has been uploaded.
Minor patches without which doing a review would be impeded are OK, but if you're just responding to review commentary and making improvements, that should be done somewhere other than in the original location. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote
Tobias Schwinger <tschwinger@neoscientists.org> writes:
The library has been updated and the following changes have been made:
You know that the library that's under review needs to remain available and unchanged during the review period, don't you? It's fine to post updates, as long as the original is still accessible through its original URL.
Maybe this should be stated explicitly. The following quote:
"A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list."
doesn't make it clear (for me, at least) that the original version has to remain available after a fix has been uploaded.
Minor patches without which doing a review would be impeded are OK, but if you're just responding to review commentary and making improvements, that should be done somewhere other than in the original location.
Well, all changes may (in certain circumstances) keep a reviewer from "fully evaluating the library". Some clarification of the guidelines would not be amiss. I added an archive with the previous version with an '_previous' suffix to the sandbox. Is it acceptable this way ? Should there be a "roll-back" (maybe adding more confusion) ? Please help. Thanks, Tobias

Tobias Schwinger <tschwinger@neoscientists.org> writes:
David Abrahams wrote:
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote
Tobias Schwinger <tschwinger@neoscientists.org> writes:
The library has been updated and the following changes have been made:
You know that the library that's under review needs to remain available and unchanged during the review period, don't you? It's fine to post updates, as long as the original is still accessible through its original URL.
Maybe this should be stated explicitly. The following quote:
"A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list."
doesn't make it clear (for me, at least) that the original version has to remain available after a fix has been uploaded. Minor patches without which doing a review would be impeded are OK, but if you're just responding to review commentary and making improvements, that should be done somewhere other than in the original location.
Well, all changes may (in certain circumstances) keep a reviewer from "fully evaluating the library". Some clarification of the guidelines would not be amiss.
In that case you're in the clear. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Well, all changes may (in certain circumstances) keep a reviewer from "fully evaluating the library". Some clarification of the guidelines would not be amiss.
Apologies for being behind the curve with this, but ideally you would have left the original review version unchanged, and posted an "_updated" version that folks could look at if they wanted. However, now it's done probably best to leave it as it is, otherwise we'll get even more churn. John.

The library has been updated and the following changes have been made: Library: -------- The "dark corner-feature" to grab the template signature of a class template has been removed, because it is not worth the trouble it can cause. It should not be in the scope of the library, anyway and should be seen as a bug fix. Documentations: --------------- The documentation has been updated to reflect the above change of the library. Several small, in-place fixes have been applied to address some of the shortcomings reported by Jody Hagins. There still is more room for improvement, but the review period is not the best time for radical changes, especially because more reviewer's thoughts could be helpful for this. Examples: --------- An example to demonstrates the customization of callbacks based on a function's input signature has been added. - interpreter.hpp [ http://tinyurl.com/bu5vn ] - interpreter_example.cpp [ http://tinyurl.com/8ryt3 ] The Jamfile in the 'example' directory has been updated to only build the two example use cases. The other examples are still built as a part of the test suit. The other example use case (which is not new) has been renamed from closure_function to function_closure: - function_closure.hpp [ http://tinyurl.com/cd4hm ] - function_closure_example.cpp [ http://tinyurl.com/9ojtj ]

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d8c7s8$9kj$1@sea.gmane.org...
The library has been updated and the following changes have been made:
A Plea from the ex - typeof review manager. IMO It should be a cast iron rule that no changes to the library implementation or documentation can be made during the review period. Note that the formal-review process document states this informally, but I think that should should be changed to Will and If a library author wants to supply bug fixes , they should be should be made available as separate versions of the library. IOW the version that is reviewed is the oriiginal one. Heres the quote. "A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list." FWIW I had a tentative review of the library lined up, but now ... which version should I be reviewing ? (e.g. I too was disappointed at the lack of examples. Apparently this is now fixed etc , etc). IOW changing a library during its review period means a lot of effort on the part of the reviewer, which most of us simply dont have time to make. regards Andy Little

Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d8c7s8$9kj$1@sea.gmane.org...
The library has been updated and the following changes have been made:
A Plea from the ex - typeof review manager.
IMO It should be a cast iron rule that no changes to the library implementation or documentation can be made during the review period. Note that the formal-review process document states this informally, but I think that should should be changed to Will and If a library author wants to supply bug fixes , they should be should be made available as separate versions of the library. IOW the version that is reviewed is the oriiginal one.
Well, it's not up to me to change the rules. But I added an archive with the previous version with an '_previous' suffix (to avoid further confusion) to the sandbox.
Heres the quote. "A proposed library should remain stable during the review period; it will just confuse and irritate reviewers if there are numerous changes. It is, however, useful to upload fixes for serious bugs right away, particularly those which prevent reviewers from fully evaluating the library. Post a notice of such fixes on the mailing list."
FWIW I had a tentative review of the library lined up, but now ... which version should I be reviewing ? (e.g. I too was disappointed at the lack of examples. Apparently this is now fixed etc , etc).
IOW changing a library during its review period means a lot of effort on the part of the reviewer, which most of us simply dont have time to make.
I'ld say, review the version you downloaded when starting. Only update, if you have enough time and want to, or if something stops you from "fully evaluating the library". Thanks, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Andy Little wrote:
I'ld say, review the version you downloaded when starting. Only update, if you have enough time and want to, or if something stops you from "fully evaluating the library".
Ok Sorry to pick on you. Exactly this happened during the typeof review. I'm trying to make amends for my poor stewardship of that. regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Andy Little wrote:
I'ld say, review the version you downloaded when starting. Only update, if you have enough time and want to, or if something stops you from "fully evaluating the library".
Ok Sorry to pick on you. Exactly this happened during the typeof review. I'm trying to make amends for my poor stewardship of that.
The only change *to the code* during the typeof review was to work-around the VC8.0 bug that showed up during the review. I felt this was important enough to fix right away. The change was minimal (a few lines of code). I believe this was done in compliance with the Boost review guidelines. We did replace the docs entirely, but there was a specific request for this, and we could have provided the old version anytime if anybody had been interested. So, IMHO, there was no "poor stewardship". One thing that might have been done during the typeof review, I think, was to extend the review period... The other minor problem I had was that we didn't get your own review ;-) Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Andy Little wrote:
I'ld say, review the version you downloaded when starting. Only update, if you have enough time and want to, or if something stops you from "fully evaluating the library".
Ok Sorry to pick on you. Exactly this happened during the typeof review. I'm trying to make amends for my poor stewardship of that.
The only change *to the code* during the typeof review was to work-around the VC8.0 bug that showed up during the review. I felt this was important enough to fix right away. The change was minimal (a few lines of code). I believe this was done in compliance with the Boost review guidelines.
We did replace the docs entirely, but there was a specific request for this, and we could have provided the old version anytime if anybody had been interested.
So, IMHO, there was no "poor stewardship".
No, in fact Arkadiy was very careful about that. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
I'ld say, review the version you downloaded when starting. Only update, if you have enough time and want to, or if something stops you from "fully evaluating the library".
Ok Sorry to pick on you.
Did you ? In fact, my impression was, that that your message was about collaborative learning from experience, which I believe is a good thing. Regards, Tobias

First, this looks very cool, and I think it will get a lot of use even from those who are a bit scared of full MPL. This is not my official review, but simply some questions/comments about the documentation, specifically the things I think of as I read it for the first time... I am not a specialist in grammar, and I have the distinct disadvantage of American English as my native language (well, most will say that South Carolina-ese is English). However, I had to read the first sentence of the MOTIVATION section three times to decipher its meaning. I think it could be better understood if it were restructured... Also, in the first paragraph of MOTIVATION, the author asserts "common applications" and "well known special cases" of which a large number of people are not familiar. IMO, if you reference a motivating case, you should explain it a bit more, or provide references to examples. I am similarly confused by the last paragraph of MOTIVATION. What is meant by "It covers the functionality of the function_traits class?" After reading the OVERVIEW and MOTIVATION, I am still at a loss for what benefit this library will provide. I can make some reasonable assumptions, but I would think that I should have a much better picture than I currently have from reading those two sections. Obviously, I am either a total idiot, or I am just having a bad day (please do not confirm the former if you know me personally). I am having a hard time groking the docs for CLASSIFICATION, especially the summary. I do not think I should have to read the full description to get an idea of what the function does, yet after reading the summary, I thought, "Hmmm... maybe a read through the details will help." To me, this indicates a little more information should be in the summary. Also, the CLASSIFCATION docs say that it tests to see if a type is an element of a set of other types, and gives several .cpp files as examples. However, after reading the entire specification for is_function_type, I have these questions... How do I build a set of types? How do I test for a type in a set? All examples show one type, not a set of types. What should happen if I put types in the set that are not function types? Should I expect a compile error, or is it up to the programmer to know specifically that the types belong in that set? For the function calls, the descriptions make some assumptions (like, it must be called with a function type). Are these suggestions for good style, or will the implementation provide a compile-time assertion, or will you ger undefined behavior if you violate the assumption? function_type_arity: Should probably put note about BOOST_FT_MAX_ARITY here (or reference the CONFIGURATION section) to make it obvious early about the max arity. What happens if you call it with a non-function? Do we get a compile time assertion? function_type_parameter: should probably say that the index starts at 0 (this is the common C/C++ method, but stating it explicitly would be helpful). It would also be helpful to be a bit more explicit about the difference between function_type_parameter and function_type_parameter_c, since not everyone groks MPL as second nature. How do functors fit in here? If a class overloads operator(), is it considered a function type? In the ENCAPSULATION section, I think the author is again making too many assumptions about the detailed knowledge of MPL. This library, while using the MPL, and imitating some aspects, does not require full knowledge of the MPL. However, the docs seem to take too much for granted, and make too many assumptions. I'd like to see more detail, especially in the descriptions. After my initial reading, I am still not entirely sure about function_type_signature. I would like to see more description information. Also, I do not like the "types" member. What is the rationale for the ordering of the types (return, [class], parameters)? Callers would have to query even more information to determine how to interpret types. Also, if you remove c-v qualifiers, how can a caller ever get what was truly passed to function_type_signature? Maybe adding something like raw_representee, or something else so that the caller can see the true T? function_type: looks very intetresting. Unfortunately, none of the thoughts/questions in my head about usability are answered by the examples. PORTABILITY: If you have not tested with BCB, maybe you should (or get someone to do it). Or, at least note that it is most likely broken on that compiler, w.r.t. function references. Specifically, BCB6 does not properly distinghush... int (func)() int (*ptr_to_func)() int (&ref_to_func)() Should the CONFIGURATION section go before the detailed descriptions of the function calls? In general, I do not like using test assertions as examples. I know lots of boost stuff uses this methodology, but it does not provide much information. If tests are used, then they should include LOTS of documentation describing exactly what is (and is not) happening, and sufficient justifications. After reading the docs, I think many will be at a loss for concrete examples of real-world use for this library. Again, in a library like this, the documentation should include LOTS more examples, and each example should be fully documented. Otherwise, the curve to usage is enormous. Finally, I'd like to see some examples that support the motivation. The author cites some reasons for the library to exist. I want proof, in the form of examples that show how difficult (or impossible) it is to do what he wants without the library, and then examples showing how the same problem is easily solved with the library. I do not think this is just unique to this library. I think it is important for all libs, hint... hint... I am under great time constraints (work, helping coach my son's baseball team, travelling every Fri-Sun with my daughter's softball team, etc.), but if I can find time to actually use the library, I'll issue a review as well. Thanks for the submission!

Hi Jody, Jody Hagins wrote:
First, this looks very cool, and I think it will get a lot of use even from those who are a bit scared of full MPL.
This is not my official review, but simply some questions/comments about the documentation, specifically the things I think of as I read it for the first time...
I am not a specialist in grammar, and I have the distinct disadvantage of American English as my native language (well, most will say that South Carolina-ese is English). However, I had to read the first sentence of the MOTIVATION section three times to decipher its meaning. I think it could be better understood if it were restructured...
OK. All I have to say for my excuse is that English is only my secondary language... So, if the first sentence is hard to understand it should be changed.
Also, in the first paragraph of MOTIVATION, the author asserts "common applications" and "well known special cases" of which a large number of people are not familiar. IMO, if you reference a motivating case, you should explain it a bit more, or provide references to examples.
Good point.
I am similarly confused by the last paragraph of MOTIVATION. What is meant by "It covers the functionality of the function_traits class?"
It means that (given the your compiler is supported by the library) all that can be done with Boost.TypeTraits' function_traits class (and more) can also be done with the FunctionTypes library.
After reading the OVERVIEW and MOTIVATION, I am still at a loss for what benefit this library will provide. I can make some reasonable assumptions, but I would think that I should have a much better picture than I currently have from reading those two sections.
What exactly is unclear ?
Obviously, I am either a total idiot, or I am just having a bad day (please do not confirm the former if you know me personally). I am having a hard time groking the docs for CLASSIFICATION, especially the summary. I do not think I should have to read the full description to get an idea of what the function does, yet after reading the summary, I thought, "Hmmm... maybe a read through the details will help." To me, this indicates a little more information should be in the summary.
Also, the CLASSIFCATION docs say that it tests to see if a type is an element of a set of other types, and gives several .cpp files as examples. However, after reading the entire specification for is_function_type, I have these questions...
How do I build a set of types? How do I test for a type in a set? All examples show one type, not a set of types.
What should happen if I put types in the set that are not function types? Should I expect a compile error, or is it up to the programmer to know specifically that the types belong in that set?
Here's a fundamental misunderstanding: There are no sets of types that can be _built_. You just _name_ a set of possible kinds of function types to test against by specifying a tag: is_function_type< function_pointer, T > Tells me if T is contained in the set of "all function pointers", which is described by the tag type function_pointer. I can ask for a superset (all types handled by the library) like this: is_function_type< any_function, T > Or a subset: is_function_type< variadic_function_pointer, T > Did you read the Tags section at all ? Was it unclear ? Where ?
For the function calls, the descriptions make some assumptions (like, it must be called with a function type). Are these suggestions for good style, or will the implementation provide a compile-time assertion, or will you ger undefined behavior if you violate the assumption?
If you violate the preconditions the behaviour is generally undefined. However, the type members won't be defined to allow better diagnostics for client code (this is currently undocumented).
function_type_arity: Should probably put note about BOOST_FT_MAX_ARITY here (or reference the CONFIGURATION section) to make it obvious early about the max arity.
BOOST_FT_MAX_ARITY applies to the whole library. Still, a reasonable point.
What happens if you call it with a non-function? Do we get a compile time assertion?
Another violated precondition. We had this above, already.
function_type_parameter: should probably say that the index starts at 0 (this is the common C/C++ method, but stating it explicitly would be helpful).
Agreed.
It would also be helpful to be a bit more explicit about the difference between function_type_parameter and function_type_parameter_c, since not everyone groks MPL as second nature.
Well, in case you don't know MPL (although the primary audience most likely will) you can still have a look at the synopsis and look for the version with non-type template parameter...
How do functors fit in here? If a class overloads operator(), is it considered a function type?
No. Is the definition really that unclear ? How could this probably work if operator() is a function template ? You can decompose a member function pointer to a parentheses operator (which implies it's already instantiated if it's a template function), though (after deduction or using some kind of typeof operator).
In the ENCAPSULATION section, I think the author is again making too many assumptions about the detailed knowledge of MPL. This library, while using the MPL, and imitating some aspects, does not require full
This _part_ of the library provides an MPL Sequence interface. There is really no point in using it without knowing the MPL and its algorithms. Yes, you can use the library without knowing MPL, but this particular part is about MPL interoperability. Sorry !
knowledge of the MPL. However, the docs seem to take too much for granted, and make too many assumptions. I'd like to see more detail, especially in the descriptions.
What do you mean with "assumption" ? Preconditions on template arguments ? As this library's classes are _slightly_ more complex in it's use than the ones of Boost.TypeTraits (in some light it can be seen as an extension) what makes you think there has to be so much more detail ?
After my initial reading, I am still not entirely sure about function_type_signature. I would like to see more description information. Also, I do not like the "types" member. What is the rationale for the ordering of the types (return, [class], parameters)? Callers would have to query even more information to determine how to interpret types.
These members are documented at all because they might be helpful in some rather rare cases - I should probably remove some of them from the documentation. The primary interface of function_type_signature<T>, however, is to use it as an MPL-Sequence.
Also, if you remove c-v qualifiers, how can a caller ever get what was truly passed to function_type_signature? Maybe adding something like raw_representee, or something else so that the caller can see the true T?
Very good point - this is unclear: it refers to top-level cv qualification of pointers. E.g: void(*const)(); The cv-qualification of "member function pointees" is _never_ dropped.
function_type: looks very intetresting. Unfortunately, none of the thoughts/questions in my head about usability are answered by the examples.
PORTABILITY: If you have not tested with BCB, maybe you should (or get someone to do it). Or, at least note that it is most likely broken on that compiler, w.r.t. function references. Specifically, BCB6 does not properly distinghush...
BCC is broken for all sorts of reasons. It is _not_ supported and does _not_ speak enough ISO-C++. Btw. I know a workaround for the problem regarding function references but the lack of partial specialization for member function pointers is much worse. I guess Boost.Typeof could be used to work around it (once it supports Borland), but I'm really not sure it's worth putting much energy into supporting this compiler (yes, I know BCB is cool for quickly building user interfaces) as the product suffers halfhearted maintainance and probably won't be around for very much longer.
int (func)() int (*ptr_to_func)() int (&ref_to_func)()
Should the CONFIGURATION section go before the detailed descriptions of the function calls?
Should it ?
In general, I do not like using test assertions as examples. I know lots of boost stuff uses this methodology, but it does not provide much information. If tests are used, then they should include LOTS of documentation describing exactly what is (and is not) happening, and sufficient justifications.
I never had problems with "assertions as examples" as a user...
After reading the docs, I think many will be at a loss for concrete examples of real-world use for this library.
It factors out existing Boost functionality in components like Bind, Lambda, ResultOf, Phoenix.... I do not want to change around these components (the library authors are free to do so of course - and I guess, and hope, some will welcome it), however, there are many more specialized situations it would be necessary to duplicate the redundancy in these components yet another time. How about a callback registration that knows from the signature of the registered function the data to call it with ? (This was my reason to need the functionality of this library) Component writers who use this library also get the benefit of a central point of configuration and being better neighbours with other components which need the same functionality in terms of compilation speed.
Again, in a library like this, the documentation should include LOTS more examples, and each example should be fully documented. Otherwise, the curve to usage is enormous.
How could someone unfamiliar with template metaprogramming (with or without using MPL) possibly be interested in using this library ? So I'm not sure you are among the intended audience. And I really would love to hear more voices from those who undoubtfully are, on what _exactly_ needs to be improved.
Finally, I'd like to see some examples that support the motivation. The author cites some reasons for the library to exist. I want proof, in the form of examples that show how difficult (or impossible) it is to do what he wants without the library, and then examples showing how the
E.g. let's extract the first parameter of a member function pointer type: Currently there is no way to do it except use Boost.Preprocessor to create a cascade of partial template specializations for every possible arity both with and without ellipsis for every calling convention required (or write it by hand, if you like ;-) ).
same problem is easily solved with the library. I do not think this is just unique to this library. I think it is important for all libs, hint... hint...
With the FunctionTypes library the above scenario looks like this: function_type_parameter_c<T,2>::type and it will compile as fast as the hand written version (the library provides preprocessed headers - and is probably even faster because plain function types and function references are transformed to pointers before using specialization to match the type). Thank you for the huge ammount of feedback ! Regards, Tobias

On Mon, 06 Jun 2005 22:37:06 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
OK. All I have to say for my excuse is that English is only my secondary language...
Well, about the closest I can come to a secondary language is C++ (though I took a few years of Latin ages and ages ago).
It means that (given the your compiler is supported by the library) all that can be done with Boost.TypeTraits' function_traits class (and more) can also be done with the FunctionTypes library.
That is a much better description.
After reading the OVERVIEW and MOTIVATION, I am still at a loss for what benefit this library will provide. I can make some reasonable assumptions, but I would think that I should have a much better picture than I currently have from reading those two sections.
What exactly is unclear ?
Well, please understand that when I read stuff as a "reviewer" I do so in a state of ignorance (some may say I live ther, but that is another story). I do not think the overview and motivation sufficiently describe the problems that the library is trying to solve. I think too many assumptions about the reader's expertise are made. The library itself is relatively easy to use, and does not require a lot of experience. However, I think the descriptions are not sufficient to show readers why they should use the library, and what problems it solves.
Here's a fundamental misunderstanding:
There are no sets of types that can be _built_.
You just _name_ a set of possible kinds of function types to test against by specifying a tag:
is_function_type< function_pointer, T >
Tells me if T is contained in the set of "all function pointers", which is described by the tag type function_pointer.
I can ask for a superset (all types handled by the library) like this:
is_function_type< any_function, T >
Or a subset:
is_function_type< variadic_function_pointer, T >
Did you read the Tags section at all ? Was it unclear ? Where ?
Yes, I read it, and I understand it. However, the documentation is a bit unclear, as it implies a set of types, not one specific tag identifier. I'm not trying to be difficult, but I am trying to find places that need improvement. In this case, "if a given type is element of a set" along with the description of Tag, where any of the tag types are allowed, can cause confusion because a set implies one or more items. I would suggest changing the documentation from using the term "set" to being more explicit about using one of the tag types. Again, however, this is just the opinion of one person. Take it for what it's worth.
For the function calls, the descriptions make some assumptions (like, it must be called with a function type). Are these suggestions for good style, or will the implementation provide a compile-time assertion, or will you ger undefined behavior if you violate the assumption?
If you violate the preconditions the behaviour is generally undefined.
Hmmm. I would prefer a compile time assertion inside the functions, if possible.
However, the type members won't be defined to allow better diagnostics for client code (this is currently undocumented).
I do not understand the above sentence.
It would also be helpful to be a bit more explicit about the difference between function_type_parameter and function_type_parameter_c, since not everyone groks MPL as second nature.
Well, in case you don't know MPL (although the primary audience most likely will) you can still have a look at the synopsis and look for the version with non-type template parameter...
I would disagree with you here. Many boost users do not know MPL. Many more probably have a cursory knowledge of MPL, but still need documentation handy to make use of it.
How do functors fit in here? If a class overloads operator(), is it considered a function type?
No. Is the definition really that unclear ?
How could this probably work if operator() is a function template ?
You can decompose a member function pointer to a parentheses operator (which implies it's already instantiated if it's a template function), though (after deduction or using some kind of typeof operator).
No, it is clear, but I would think that some notes about operator(), boost::function, and boost::lambda would be appropriate, since some folks may want to use them in some ways related to function_types.
knowledge of the MPL. However, the docs seem to take too much for granted, and make too many assumptions. I'd like to see more detail, especially in the descriptions.
What do you mean with "assumption" ? Preconditions on template arguments ?
I think interface documentation should make the lowest common assumptions. Not everyone is familiar with the types of problems this library is trying to solve. I am sure you are not merely targeting an audience of people who could implement this library themselves, but those who would like this functionality without implementing the details. FWIW, most boost libraries fail in this regard, in my opinion. Library documentation should make as few assumptions about the knowledge and experience of the user as possible.
As this library's classes are _slightly_ more complex in it's use than the ones of Boost.TypeTraits (in some light it can be seen as an extension) what makes you think there has to be so much more detail ?
Because the current detail is not sufficient ;-) Seriously, I think this library is very much in the reach of a boost newbie to use. However, the documentation and examples are written for a more experienced audience. Thus, I do not think the documentation fits a significant segment of potential users. If you do not intend to target relatively new users to boost, then I guess you can leave it alone.
After my initial reading, I am still not entirely sure about function_type_signature. I would like to see more description information. Also, I do not like the "types" member. What is the rationale for the ordering of the types (return, [class], parameters)? Callers would have to query even more information to determine how to interpret types.
These members are documented at all because they might be helpful in some rather rare cases - I should probably remove some of them from the documentation.
I like them there, but they do introduce questions about usage. In particular, you need to leave "kind" because as far as I see, it is the only way to get the tag identity of a signature. I question the "types" because I think it could be a little easier to get the return type, and the parameters without the optional class sandwiched inbetween.
BCC is broken for all sorts of reasons. It is _not_ supported and does _not_ speak enough ISO-C++. Btw. I know a workaround for the problem regarding function references but the lack of partial specialization for member function pointers is much worse.
Fine with me. I've been advocating dropping compilers that are too broken, or require too many workarounds, for a while now. However, BCB is used by a number of boosters, and until Borland comes out with something else, they are a bit stuck. Maybe an explicit note about BCB would be a good addition to that section.
Should the CONFIGURATION section go before the detailed descriptions of the function calls?
Should it ?
Dunno. I had questions about the calling convention and arity long before I got to the section called CONFIGURATION. It was not obvious at all when I looked at the table of contents to the left that I should go to the CONFIGURATION section to answer those questions.
In general, I do not like using test assertions as examples. I know lots of boost stuff uses this methodology, but it does not provide much information. If tests are used, then they should include LOTS of documentation describing exactly what is (and is not) happening, and sufficient justifications.
I never had problems with "assertions as examples" as a user...
Good for you. I doubt that is the case for everyone. Most of these tests are unit tests, which do not necessarily show typical use cases. In my opinion, I'd like to see typical real-life use cases as examples. In particular, something that solves the main reasons for the library existence, so I can see true ways of using the library.
How about a callback registration that knows from the signature of the
registered function the data to call it with ?
(This was my reason to need the functionality of this library)
This seems like a reasonable example, and will probably use most of the interface as well.
How could someone unfamiliar with template metaprogramming (with or without using MPL) possibly be interested in using this library ?
How could someone unfamiliar with socket programming possibly be interested in a socket library? How could someone unfamiliar with signals/slots possibly be interested in the signals library? I use a number of boost libs on a daily basis. However, I did not start using them because I was already an expert in that domain. Primarily, I started looking at some documentation, and it then hit me how I could use the lib to solve some of my own problems (or later, when a problem came up, I rememebered something I read about a lib). I think you are approaching the documentation from the standpoint of someone who already knows the details of implementing and using the library, and not from the POV of someone who does not even know if they should use the library. I think we should strive to meet users where they are, and through documentation, bring them to the level of the developer.
So I'm not sure you are among the intended audience. And I really would love to hear more voices from those who undoubtfully are, on what _exactly_ needs to be improved.
Don't be so sure ;-> I'm not exactly the novice for which you seem to take me. However, I do believe that documentation should be written in that vein (and I also believe documentation should be reviewed in the same vein). If you still think I've not given enough exact information, then I apologize, and hope that someone else can make it more clear. Also, please do not fall into the trap that some other submitters have fallen into: reviews are not attacks on people, but ideas.
Finally, I'd like to see some examples that support the motivation. The author cites some reasons for the library to exist. I want proof, in the form of examples that show how difficult (or impossible) it is to do what he wants without the library, and then examples showing how the
E.g. let's extract the first parameter of a member function pointer type:
Currently there is no way to do it except use Boost.Preprocessor to create a cascade of partial template specializations for every possible arity both with and without ellipsis for every calling convention required (or write it by hand, if you like ;-) ).
same problem is easily solved with the library. I do not think this is just unique to this library. I think it is important for all libs, hint... hint...
With the FunctionTypes library the above scenario looks like this:
function_type_parameter_c<T,2>::type
and it will compile as fast as the hand written version (the library provides preprocessed headers - and is probably even faster because plain function types and function references are transformed to pointers before using specialization to match the type).
Actually, this is a great example, but note that it will bring up more questions (e.g., why 2 and not 1? and how would I do it if I did not know it was a member-function-ptr type? -- which is the basis for my question about "types" since it requires some knowledge about the optional class element of the sequence). I'm really looking forward to the callback registration example. I think it is similar to something I wrote to help automate registration of slots with the appropriate signals (though probably more general).
Thank you for the huge ammount of feedback !
You bet. I only hope some of it turns out to be valueable, and not just "reply-fodder." Thanks again for your submission, and desire to enhance open source libraries.

On Tue, 7 Jun 2005 02:04:46 -0400 Jody Hagins <jody-boost-011304@atdesk.com> wrote:
If you still think I've not given enough exact information, then I apologize, and hope that someone else can make it more clear. Also, please do not fall into the trap that some other submitters have fallen into: reviews are not attacks on people, but ideas.
Actually, I wrote the wrong thing above. They are not supposed to be attacks at all, but my meaning is that we are reviewing the ideas, design, documentation, implementation, etc, but not the person. Please don't take anything I write personally (or anyone else, for that matter). I guess I still remember too well the exchanges between Jonathan and Andreas, and I want to avoid something even remotely similar.

Jody Hagins wrote:
On Mon, 06 Jun 2005 22:37:06 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
It means that (given the your compiler is supported by the library) all that can be done with Boost.TypeTraits' function_traits class (and more) can also be done with the FunctionTypes library.
That is a much better description.
Seems like we have a fundamentally different taste when it comes to documentation... I find the documentation too long already, for that matter.
After reading the OVERVIEW and MOTIVATION, I am still at a loss for what benefit this library will provide. I can make some reasonable assumptions, but I would think that I should have a much better picture than I currently have from reading those two sections.
What exactly is unclear ?
Well, please understand that when I read stuff as a "reviewer" I do so in a state of ignorance (some may say I live ther, but that is another story). I do not think the overview and motivation sufficiently
Are you sure you're not overdoing it ?
describe the problems that the library is trying to solve. I think too many assumptions about the reader's expertise are made. The library itself is relatively easy to use, and does not require a lot of experience. However, I think the descriptions are not sufficient to show readers why they should use the library, and what problems it solves.
I just re-read the 'Overview' section trying to imagine I would not know much about it and it still gives me a clear impression of what the library does. The only thing I see right away is there could be some examples for which properties to inspect. I agree the 'Motivation' section can be improved and I will consider your points once I find the time to rewrite it.
Here's a fundamental misunderstanding:
There are no sets of types that can be _built_.
You just _name_ a set of possible kinds of function types to test against by specifying a tag:
is_function_type< function_pointer, T >
Tells me if T is contained in the set of "all function pointers", which is described by the tag type function_pointer.
I can ask for a superset (all types handled by the library) like this:
is_function_type< any_function, T >
Or a subset:
is_function_type< variadic_function_pointer, T >
Did you read the Tags section at all ? Was it unclear ? Where ?
Yes, I read it, and I understand it. However, the documentation is a bit unclear, as it implies a set of types, not one specific tag identifier. I'm not trying to be difficult, but I am trying to find places that need improvement. In this case, "if a given type is element of a set" along with the description of Tag, where any of the tag types are allowed, can cause confusion because a set implies one or more items. I would suggest changing the documentation from using the term "set" to being more explicit about using one of the tag types.
Does perhaps it help to say "infinite sets" ? Or even "infinite immutable sets" ? Every occurence of "set of types" is almost immediately followed by "specified by one of the tag types" or alike, where "tag types" is a hyperlink to the description.
Again, however, this is just the opinion of one person. Take it for what it's worth.
Well, I think it takes more than two people's opinion (with very different tastes and one of them being the author) to get a clear picture how to get the documentation right. However, I do appreciate your feedback. And (to cover another paragraph further below and the follow-up) do _not_ take this as a personal offense or whatever. It's valuable (even I do not agree in every point and just reply to some of them: I have to think about it one more time and it clearifies the rationale behind things, which is sometimes based on intuition)...
For the function calls, the descriptions make some assumptions (like, it must be called with a function type). Are these suggestions for good style, or will the implementation provide a compile-time assertion, or will you ger undefined behavior if you violate the assumption?
If you violate the preconditions the behaviour is generally undefined.
Hmmm. I would prefer a compile time assertion inside the functions, if possible.
...like this one ;-). Actually my first version used static assertions...
However, the type members won't be defined to allow better diagnostics for client code (this is currently undocumented).
I do not understand the above sentence.
This version doesn't use static assertions but e.g. function_type_arity<int> has no member named 'type' or 'value' This tells the user that function_type_arity sees a wrong argument. The line number of the error message is within the user's code (where it happens) and not somewhere within the Function Types library (as it would be using static assert, which further stops the compilation process in some contexts). In fact, I did not invent this technique, it can be said to be common practice...
It would also be helpful to be a bit more explicit about the difference between function_type_parameter and function_type_parameter_c, since not everyone groks MPL as second nature.
Well, in case you don't know MPL (although the primary audience most likely will) you can still have a look at the synopsis and look for the version with non-type template parameter...
I would disagree with you here. Many boost users do not know MPL. Many more probably have a cursory knowledge of MPL, but still need documentation handy to make use of it.
I believe you did not get my point, here: I'm trying to say that a user who does not know MPL would not know type to pass for an "Index" and thus use the version expecting a non-type template parameter of type std::size_t instead. This does not assume MPL knowledge, just a bit of intelligence ;-).
How do functors fit in here? If a class overloads operator(), is it considered a function type?
No. Is the definition really that unclear ?
How could this probably work if operator() is a function template ?
You can decompose a member function pointer to a parentheses operator (which implies it's already instantiated if it's a template function), though (after deduction or using some kind of typeof operator).
No, it is clear, but I would think that some notes about operator(), boost::function, and boost::lambda would be appropriate, since some folks may want to use them in some ways related to function_types.
Is there a note in the TypeTraits documentation that remove_pointer cannot be used to retrieve the pointee type of a smart pointer ? No, because it's clear that it is a low-level facility true to the very nature of the type system (in fact, making remove_pointer do the above thing would severaly screw up things). As mentioned in my previous post, components such as Lambda, Function and Bind (or in some ways similar but perhaps more specialized) components are potential clients of this library. I am having difficulties to come up with good use cases here (and these components do not have that much to do with each other from a user's perspective, except that they all deal with functions in one way or the other): The parentheses-operator of Lambda-functors is a function template (so I really can't see a useful application in this direction). It's rather trivial to use it with boost::function (assuming the "preferred syntax") via partial specialization, e.g: template< typename Function, std::size_t Index > struct func_param : function_type_parameter_c<Function,Index> { }; template< typename Sig, std::size_t Index > struct func_param< function<Sig>, Index > : function_type_parameter_c<Sig,Index> { }; to do e.g. concept checking: template< /*...*/ typename CompareFunction > void my_algorithm( /*...*/ CompareFunction compare ) { BOOST_MPL_ASSERT(( is_same< typename func_param<CompareFunction,0>::type , typename func_param<CompareFunction,1>::type > )); // ... } I'm not convinced of this is of any use either, though. Using a pointer to parentheses-operator (on functors where it is not a template function) probably gives a nice example.
knowledge of the MPL. However, the docs seem to take too much for granted, and make too many assumptions. I'd like to see more detail, especially in the descriptions.
What do you mean with "assumption" ? Preconditions on template arguments ?
I think interface documentation should make the lowest common assumptions. Not everyone is familiar with the types of problems this library is trying to solve. I am sure you are not merely targeting an audience of people who could implement this library themselves, but those who would like this functionality without implementing the details.
Someone who doesn't know a problem is not looking to solve it...
FWIW, most boost libraries fail in this regard, in my opinion. Library documentation should make as few assumptions about the knowledge and experience of the user as possible.
Well, I disagree here: Is the decision whether or not to use a software components really a matter of being able to implement it ? I believe this is a very onesided view: Given enough time, pretty much everything is implementable and finding an elegant and suitable design to encapsulate things can be much harder. Everyone knows the differences of file systems on different platforms and can come up with a half-baked solution to make things portable and I guess everyone who uses lexical_cast knows how to convert integers to strings without it. So why are we using generic components at all ? Because it simplifies our code and makes it more expressive, probably adds to its runtime efficiency, because we can subscribe to the design and because it's a lot of work to get things right out on our own and because the libraries handle subtle problems we would only become aware of when implementing things ourselves.
As this library's classes are _slightly_ more complex in it's use than the ones of Boost.TypeTraits (in some light it can be seen as an extension) what makes you think there has to be so much more detail ?
Because the current detail is not sufficient ;-) Seriously, I think this library is very much in the reach of a boost newbie to use. However, the documentation and examples are written for a more experienced audience. Thus, I do not think the documentation fits a significant segment of potential users. If you do not intend to target relatively new users to boost, then I guess you can leave it alone.
Well, I do - but it's probably not the very best starting point to learn about template metaprogramming (and that's why there are so many links to other places in the boost documenation). Only some parts of the interface, however, assume you are familiar with MPL. And you don't have to read up the concepts of MPL to use most of the library. It's helpful to know in case it is used in conjunction with MPL, though.
After my initial reading, I am still not entirely sure about function_type_signature. I would like to see more description information. Also, I do not like the "types" member. What is the rationale for the ordering of the types (return, [class], parameters)? Callers would have to query even more information to determine how to interpret types.
These members are documented at all because they might be helpful in some rather rare cases - I should probably remove some of them from the documentation.
I like them there, but they do introduce questions about usage. In particular, you need to leave "kind" because as far as I see, it is the only way to get the tag identity of a signature.
You should not use it directly in 99% of all cases and use is_function_kind<Tag, T> instead. Actually there are no public functions to properly compare the tags so you should stay away from this.
I question the "types" because I think it could be a little easier to get the return type, and the parameters without the optional class sandwiched inbetween.
Actually it _is_ a lot easier: function_type_signature<T> is a model of MPL Sequence. No need to mess with the 'types' member, unless for optimization (e.g. you want a mutable sequence and don't want dependencies to function_type.hpp).
BCC is broken for all sorts of reasons. It is _not_ supported and does _not_ speak enough ISO-C++. Btw. I know a workaround for the problem regarding function references but the lack of partial specialization for member function pointers is much worse.
Fine with me. I've been advocating dropping compilers that are too broken, or require too many workarounds, for a while now. However, BCB is used by a number of boosters, and until Borland comes out with something else, they are a bit stuck. Maybe an explicit note about BCB would be a good addition to that section.
Well, BCB is not listed among the supported compilers - this should be enough IMO. I plan on applying some broken compiler workarounds although I am not too sure which ones, yet. I hope this review will clearify the requirements. AFAIK things are not likely to get much better with BCC and it will be around for some more time (even though Borland stops the development entirely) - a good reason to provide (at least limited) support for it.
Should the CONFIGURATION section go before the detailed descriptions of the function calls?
Should it ?
Dunno. I had questions about the calling convention and arity long before I got to the section called CONFIGURATION. It was not obvious at all when I looked at the table of contents to the left that I should go to the CONFIGURATION section to answer those questions.
Good point.
In general, I do not like using test assertions as examples. I know lots of boost stuff uses this methodology, but it does not provide much information. If tests are used, then they should include LOTS of documentation describing exactly what is (and is not) happening, and sufficient justifications.
I never had problems with "assertions as examples" as a user...
Good for you. I doubt that is the case for everyone. Most of these tests are unit tests, which do not necessarily show typical use cases. In my opinion, I'd like to see typical real-life use cases as examples. In particular, something that solves the main reasons for the library existence, so I can see true ways of using the library.
The problem is that most real-world use cases do involve more of the library than just a single function, so it'll be harder to understand what a particular function does, this way.
How about a callback registration that knows from the signature of the
registered function the data to call it with ?
(This was my reason to need the functionality of this library)
This seems like a reasonable example, and will probably use most of the interface as well.
I'll try to add more real-world examples.
How could someone unfamiliar with template metaprogramming (with or without using MPL) possibly be interested in using this library ?
How could someone unfamiliar with socket programming possibly be interested in a socket library? How could someone unfamiliar with
Well this should sound: "how could someone unfamiliar with network programming be interested in a socket library ?"...
signals/slots possibly be interested in the signals library? I use a number of boost libs on a daily basis. However, I did not start using them because I was already an expert in that domain. Primarily, I started looking at some documentation, and it then hit me how I could use the lib to solve some of my own problems (or later, when a problem came up, I rememebered something I read about a lib).
I think you are approaching the documentation from the standpoint of someone who already knows the details of implementing and using the library, and not from the POV of someone who does not even know if they should use the library. I think we should strive to meet users where they are, and through documentation, bring them to the level of the developer.
...however I get your point. I have to think about how to improve this.
So I'm not sure you are among the intended audience. And I really would love to hear more voices from those who undoubtfully are, on what _exactly_ needs to be improved.
Don't be so sure ;-> I'm not exactly the novice for which you seem to take me. However, I do believe that documentation should be written in that vein (and I also believe documentation should be reviewed in the same vein).
In fact, I don't think a pathological interest in torturing compilers is a must to be a good programmer. It leads to some interesting techniques regarding both design and implementation and because of this boost folks appreciate these (at first glance) tricky techniques. This said, I just mentioned some doubt if the novice you are (or not are, but pretending to be for the purpose of bulletproofing the documentation) has a need for this library. No intentional offense, here. <snip>
E.g. let's extract the first parameter of a member function pointer type:
Currently there is no way to do it except use Boost.Preprocessor to create a cascade of partial template specializations for every possible arity both with and without ellipsis for every calling convention required (or write it by hand, if you like ;-) ).
same problem is easily solved with the library. I do not think this is just unique to this library. I think it is important for all libs, hint... hint...
With the FunctionTypes library the above scenario looks like this:
function_type_parameter_c<T,2>::type
and it will compile as fast as the hand written version (the library provides preprocessed headers - and is probably even faster because plain function types and function references are transformed to pointers before using specialization to match the type).
Actually, this is a great example, but note that it will bring up more questions (e.g., why 2 and not 1?
Because it was late in my timezone yesterday and I tend to turn into an idiot when tired ;-): It should be 0 (the first parameter) not 2 (the third parameter) !
and how would I do it if I did not know it was a member-function-ptr type?
The same way.
-- which is the basis for my question about "types" since it requires some knowledge about the optional class element of the sequence).
When using 'function_type_signature' (or its 'types' member, which, as stated above, is not recommended) it does make a difference (because these are sequences containing all sub-types not just the parameter types). In case you need an MPL Sequence of all parameter types there is the convenience function 'function_type_parameters' (plural).
I'm really looking forward to the callback registration example. I think it is similar to something I wrote to help automate registration of slots with the appropriate signals (though probably more general).
I hope I'll get it done in the next couple of days.
Thank you for the huge ammount of feedback !
You bet. I only hope some of it turns out to be valueable, and not just "reply-fodder."
As stated above, even "reply-fodder" helps in enhancing things. And yes there are valuable points among it.
Thanks again for your submission, and desire to enhance open source libraries.
You're welcome. Regards, Tobias

Seems like we have a fundamentally different taste when it comes to documentation...
Probably.
Are you sure you're not overdoing it ?
Obviously, I don't think so ;-) However, it's your submission, and you have the final say of what you are willing to add. All I can do is provide my opinion (which, no matter how many words I write, is still ONE opinion -- albeit an important opinion to me).
Does perhaps it help to say "infinite sets" ? Or even "infinite immutable sets" ?
Every occurence of "set of types" is almost immediately followed by "specified by one of the tag types" or alike, where "tag types" is a hyperlink to the description.
To me, a set of types is just the wrong description, as it conveys something completely different. If you still want to use that term, I think the TAGTYPES section should more explicitly explain this concept. Currently, it starts out talking about "kinds" and then later, slips in the term "sets" almost as an afterthought, though this is an important concept (and it is something that actually cnofused me -- I thought I was supposed to combine the tag-types into a set of 1 or more tag-types and check if a function belonged to any of those tag-types) After thinking about it a little, maybe a small change would make the "set" concept more clear. Currently, you have this sentence: The Function Types library uses tag types to describe different kinds of function types, and arbitrary supersets of these and their inverse. Maybe changing to to something like: The Function Types library uses tag types to describe different kinds of function types. Each tag type names a particular set of similar function types. For example, given these types: typedef void (*foo_t)(int); typedef int (*bar_t)(std::string const &); struct blarg_t { void foo(); }; struct foobar_t { int bar(double) const; } foo_t and bar_t (along with all other non-member/static functions) are elements of the set named plain_function. Likewise, &blarg_t::foo and &foobar_t::bar (along with all other member function pointers) are elements of the set named member_function_pointer. In addition, &foobar_t::bar is also a member of the set const_member_function_pointer. Yes, you may be stating the obvious... for some people, but it sure makes it more clear when you use the terms later. Also, the obvious is in the mind of the reader, based on previous experience with overloaded terms like "set." I also think the documentation should provide a Venn diagram, or some other method to easily identify the superset membership of the named tag type sets. Specifically, it is not obvious how the library differentiates function_pointer and member_function_pointer. Some may think that member_function_pointer is a subset of function_pointer (even though one of the examples has an assertion somewhere that checks this relationship).
This version doesn't use static assertions but e.g.
function_type_arity<int> has no member named 'type' or 'value'
This tells the user that function_type_arity sees a wrong argument.
The line number of the error message is within the user's code (where it happens) and not somewhere within the Function Types library (as it would be using static assert, which further stops the compilation process in some contexts).
In fact, I did not invent this technique, it can be said to be common practice...
Compile time assertion, or compiler error: doesn't matter, as long as "bad" code is not silently accepted. I have seen many examples of metafunction programming where "assumptions" are violated, yet silently accepted, only to yield bad runtime errors. Metafunction programming errors should be found at compile time, not run time. Users may appreciate an explicit notation.
I believe you did not get my point, here:
I'm trying to say that a user who does not know MPL would not know type to pass for an "Index" and thus use the version expecting a non-type template parameter of type std::size_t instead. This does not assume MPL knowledge, just a bit of intelligence ;-).
An even more dangerous assumption ;-) Maybe reordering the two function_type_parameter functions would help, since everyone should be familiar with the size_t version. Once they read that section, they will then come to the MPL-ish section.
Is there a note in the TypeTraits documentation that remove_pointer cannot be used to retrieve the pointee type of a smart pointer ?
No, because it's clear that it is a low-level facility true to the very nature of the type system (in fact, making remove_pointer do the above thing would severaly screw up things).
Apparantly it is not so clear. A simple search through the boost archives will show several questions about how to remove the pointer from a smart pointer. Maybe the docs for type_traits should include some pointers to boost::pointee. However, the type_traits library is not up for review here, so I'm not that concerned about its documentation at this moment. On that note, I'm not sure we should use existing documentation as a minimal standard. I think we should strive to make all documentation as clear as possible. In this case, your library is called function_types. Some may consider classes that provide operator() a function type. Others would consider boost::function and boost::lambda function types as well. I think it is important to provide as much information as possible, especially for how boost libraries relate and can (not) be used together. No, I'm not looking for an exhaustive list. However, I would think that considering possible relationships is important, especially with other boost libs.
I am having difficulties to come up with good use cases here (and these components do not have that much to do with each other from a user's perspective, except that they all deal with functions in one way or the other):
I've not spent much time thinking about use cases either, but I know those things exist, and are related to "function types" so I am curious as to how they are related. Also, let's say I have some "function types" some of which are true function types, and others which are boost::function. All I have is function types (and boost::function goes a long way to make sure I can use it like a real function without having to know it is a function type). typedef boost::function<int (double, char const *)> foo_t; What will happen if I pass foo_t to the function_types library? Should boost_function be an additional tag-type, which you get by maybe including another header file? It seems that I should be able to use the function type library to unify parameter access, etc. For example, function_type_parameter_c< foo_t, 1 >::type should work whether foo_t is typedef'd as above, or as: typedef int foo_t(double, char const *);
I'm not convinced of this is of any use either, though.
Using a pointer to parentheses-operator (on functors where it is not a template function) probably gives a nice example.
Again, I'm not saying that there are necessarily uses for any of this. However, Boost is a collection of libraries. If the function_type library were a stand alone library, it would not matter, but it is part of a collection, and I think any relationships with other libs should be documented (and any possible implementation relationships should be explored for possible implementation -- for example boost::function).
Someone who doesn't know a problem is not looking to solve it...
The problem may already be solved differently (either at runtime, or via code generators, etc). Most likely, people coming to boost are looking for a reason to START using metatemplate programming. From reading the list for a long time, I'd be willing to bet that most boost users came to boost for one library in particular (probably smart pointer and regex), and then started seeing uses for other libs.
FWIW, most boost libraries fail in this regard, in my opinion. Library documentation should make as few assumptions about the knowledge and experience of the user as possible.
Well, I disagree here:
Is the decision whether or not to use a software components really a matter of being able to implement it ?
I believe this is a very onesided view: Given enough time, pretty much
everything is implementable and finding an elegant and suitable design to encapsulate things can be much harder.
Everyone knows the differences of file systems on different platforms and can come up with a half-baked solution to make things portable and I guess everyone who uses lexical_cast knows how to convert integers to strings without it.
So why are we using generic components at all ?
Because it simplifies our code and makes it more expressive, probably adds to its runtime efficiency, because we can subscribe to the design and because it's a lot of work to get things right out on our own and because the libraries handle subtle problems we would only become aware of when implementing things ourselves.
I agree with everything you said here, so I'm not sure where we disagree...
I like them there, but they do introduce questions about usage. In particular, you need to leave "kind" because as far as I see, it is the only way to get the tag identity of a signature.
You should not use it directly in 99% of all cases and use
is_function_kind<Tag, T>
Hmmm. I do not see this anywhere in the online documentation.
instead. Actually there are no public functions to properly compare the tags so you should stay away from this.
Actually, I was thinking of something more along the line of... is_function_type< function_type_signature< foo_t >::kind, bar_t >::value though function_kind would be nicer...
I question the "types" because I think it could be a little easier to get the return type, and the parameters without the optional class sandwiched inbetween.
Actually it _is_ a lot easier:
function_type_signature<T>
is a model of MPL Sequence.
No need to mess with the 'types' member, unless for optimization (e.g. you want a mutable sequence and don't want dependencies to function_type.hpp).
I guess, from just reading, I do not see how you know if you should "skip" the optional "class" member of the sequence, without some sort of conditional code.
The problem is that most real-world use cases do involve more of the library than just a single function, so it'll be harder to understand what a particular function does, this way.
Right. I think we are on the same page here. Leave the current examples, but add a unified, real world example as well.
I'll try to add more real-world examples.
Great! Just between you and me, this is a truely lacking area in most boost libraries (with a few exceptions, like smart pointer).
In fact, I don't think a pathological interest in torturing compilers is a must to be a good programmer. It leads to some interesting
That's great! I'm going to have to remember that one!
This said, I just mentioned some doubt if the novice you are (or not are, but pretending to be for the purpose of bulletproofing the documentation) has a need for this library. No intentional offense, here.
I'm not necessarily pretending, because I do not use these techniques very often. However, I am trying to read with the view of "how can the docs be improved", rather than "do the docs meet a minimum requirement." However, you gotta try hard to truly offend me. Unfortunately, I've found that I can offend people without even trying, which is one reason I tend to stay off the radar...

Jody Hagins wrote:
Seems like we have a fundamentally different taste when it comes to documentation...
Probably.
Are you sure you're not overdoing it ?
Obviously, I don't think so ;-) However, it's your submission, and you have the final say of what you are willing to add. All I can do is provide my opinion (which, no matter how many words I write, is still ONE opinion -- albeit an important opinion to me).
Does perhaps it help to say "infinite sets" ? Or even "infinite immutable sets" ?
Every occurence of "set of types" is almost immediately followed by "specified by one of the tag types" or alike, where "tag types" is a hyperlink to the description.
To me, a set of types is just the wrong description, as it conveys something completely different. If you still want to use that term, I think the TAGTYPES section should more explicitly explain this concept. Currently, it starts out talking about "kinds" and then later, slips in the term "sets" almost as an afterthought, though this is an important concept (and it is something that actually cnofused me -- I thought I was supposed to combine the tag-types into a set of 1 or more tag-types and check if a function belonged to any of those tag-types)
OK - this is a concrete hint of what goes wrong and gives me an idea of what to change.
After thinking about it a little, maybe a small change would make the "set" concept more clear. Currently, you have this sentence:
The Function Types library uses tag types to describe different kinds of function types, and arbitrary supersets of these and their inverse.
Maybe changing to to something like:
The Function Types library uses tag types to describe different kinds of function types. Each tag type names a particular set of similar function types. For example, given these types: typedef void (*foo_t)(int); typedef int (*bar_t)(std::string const &); struct blarg_t { void foo(); }; struct foobar_t { int bar(double) const; } foo_t and bar_t (along with all other non-member/static functions) are elements of the set named plain_function. Likewise, &blarg_t::foo and &foobar_t::bar (along with all other member function pointers) are elements of the set named member_function_pointer. In addition, &foobar_t::bar is also a member of the set const_member_function_pointer.
Yes, you may be stating the obvious... for some people, but it sure makes it more clear when you use the terms later. Also, the obvious is in the mind of the reader, based on previous experience with overloaded terms like "set."
This seems good.
I also think the documentation should provide a Venn diagram, or some other method to easily identify the superset membership of the named tag type sets. Specifically, it is not obvious how the library differentiates function_pointer and member_function_pointer. Some may think that member_function_pointer is a subset of function_pointer (even though one of the examples has an assertion somewhere that checks this relationship).
I see.
This version doesn't use static assertions but e.g.
function_type_arity<int> has no member named 'type' or 'value'
This tells the user that function_type_arity sees a wrong argument.
The line number of the error message is within the user's code (where it happens) and not somewhere within the Function Types library (as it would be using static assert, which further stops the compilation process in some contexts).
In fact, I did not invent this technique, it can be said to be common practice...
Compile time assertion, or compiler error: doesn't matter, as long as
Well, I believe good error reporting does matter. That's why the current design was chosen.
"bad" code is not silently accepted. I have seen many examples of metafunction programming where "assumptions" are violated, yet silently accepted, only to yield bad runtime errors. Metafunction programming errors should be found at compile time, not run time. Users may appreciate an explicit notation.
There is no runtime behaviour. If you violate preconditions you get an error and the library takes some effort to give you a nice one, too.
I believe you did not get my point, here:
I'm trying to say that a user who does not know MPL would not know type to pass for an "Index" and thus use the version expecting a non-type template parameter of type std::size_t instead. This does not assume MPL knowledge, just a bit of intelligence ;-).
An even more dangerous assumption ;-) Maybe reordering the two function_type_parameter functions would help, since everyone should be familiar with the size_t version. Once they read that section, they will then come to the MPL-ish section.
Probably the more subtle point is the most important here: making these sections more explicit could help.
Is there a note in the TypeTraits documentation that remove_pointer cannot be used to retrieve the pointee type of a smart pointer ?
No, because it's clear that it is a low-level facility true to the very nature of the type system (in fact, making remove_pointer do the above thing would severaly screw up things).
Apparantly it is not so clear. A simple search through the boost archives will show several questions about how to remove the pointer from a smart pointer. Maybe the docs for type_traits should include
I know... And I never really understood it ;-).
some pointers to boost::pointee. However, the type_traits library is not up for review here, so I'm not that concerned about its documentation at this moment.
On that note, I'm not sure we should use existing documentation as a minimal standard. I think we should strive to make all documentation as clear as possible.
The "maximum standard", however, is a very subjective thing - and existing documentation of a library dealing with a similar topic may serve as an orientation.
In this case, your library is called function_types. Some may consider classes that provide operator() a function type. Others would consider boost::function and boost::lambda function types as well. I think it is
Well, there is a definition right in the beginning. I can add an explicit exclusion of class types to it.
important to provide as much information as possible, especially for how boost libraries relate and can (not) be used together. No, I'm not looking for an exhaustive list. However, I would think that considering possible relationships is important, especially with other boost libs.
Noted.
I am having difficulties to come up with good use cases here (and these components do not have that much to do with each other from a user's perspective, except that they all deal with functions in one way or the other):
I've not spent much time thinking about use cases either, but I know those things exist, and are related to "function types" so I am curious as to how they are related.
Also, let's say I have some "function types" some of which are true function types, and others which are boost::function. All I have is function types (and boost::function goes a long way to make sure I can use it like a real function without having to know it is a function type).
typedef boost::function<int (double, char const *)> foo_t;
What will happen if I pass foo_t to the function_types library?
It depends on the function you pass it to, but it is not considered to be a function type.
Should boost_function be an additional tag-type, which you get by maybe including another header file?
No. This library only models the type system. Boost.Function (and alike) should be allowed to use this library in the future (as higher-level components use lower-level components not the other way around). However, here are two possible recipes of how a Boost.Function could be analyzed with this library: 1. AFAIK Boost.Function uses a non-templated parentheses operator therefore you can apply a typeof operator (or Boost.Typeof) on a pointer to its operator() function (you can do this for any functor with a non-template operator()). 2.a. The "preferred syntax" is a template parametrized with a (plain) function type to describe its signature. Partial specialization or overloading can be used to get this template argument from an instantiation of 'boost::function'. 2.b. The "compatible syntax" is a template parametrized with the sub-types of its signature. There is an (even documented) "corner-case-feature" of 'function_type_signature' that allows you to grab the argument list from a class template instantiation. Because of this 'boost::functionN' is a valid signature for 'function_type' (given that 'function_type_signature.hpp' is included) together with the tag 'plain_function' to get the same type that a (preferred-syntax) 'boost::function' is instantiated with.
It seems that I should be able to use the function type library to unify parameter access, etc. For example, function_type_parameter_c< foo_t, 1 >::type should work whether foo_t is typedef'd as above, or as: typedef int foo_t(double, char const *);
As explained above the implementation for something like this for Boost.Function is rather simple. If you wanted to implement a utility for unified parameter access - it's pretty much about probing conventions and this is really something totally different than what this library is about. However it can help you a great deal for supporting the "real" functions. While I do not doubt the usefulness of such a utility, we need a fundament for things like this first, true to the nature of the type system. TypeTraits lacks to support the types handled by this library in "full beauty", so this is the reason why it exists. It's quite bit of work that every developer of components, like the one mentioned above, has to spend on writing a more-or-less complete version of this library as an implementation detail. Not to mention compile time efficiency if many of them are used simultanously.
I'm not convinced of this is of any use either, though.
Using a pointer to parentheses-operator (on functors where it is not a template function) probably gives a nice example.
Again, I'm not saying that there are necessarily uses for any of this. However, Boost is a collection of libraries. If the function_type library were a stand alone library, it would not matter, but it is part of a collection, and I think any relationships with other libs should be documented (and any possible implementation relationships should be explored for possible implementation -- for example boost::function).
Right. The upcoming versions of these libraries and of course the ones yet to come should be encouraged to use this.
Someone who doesn't know a problem is not looking to solve it...
The problem may already be solved differently (either at runtime, or via code generators, etc). Most likely, people coming to boost are looking for a reason to START using metatemplate programming. From reading the list for a long time, I'd be willing to bet that most boost users came to boost for one library in particular (probably smart pointer and regex), and then started seeing uses for other libs.
FWIW, most boost libraries fail in this regard, in my opinion. Library documentation should make as few assumptions about the knowledge and experience of the user as possible.
Well, I disagree here:
Is the decision whether or not to use a software components really a matter of being able to implement it ?
I believe this is a very onesided view: Given enough time, pretty much
everything is implementable and finding an elegant and suitable design to encapsulate things can be much harder.
Everyone knows the differences of file systems on different platforms and can come up with a half-baked solution to make things portable and I guess everyone who uses lexical_cast knows how to convert integers to strings without it.
So why are we using generic components at all ?
Because it simplifies our code and makes it more expressive, probably adds to its runtime efficiency, because we can subscribe to the design and because it's a lot of work to get things right out on our own and because the libraries handle subtle problems we would only become aware of when implementing things ourselves.
I agree with everything you said here, so I'm not sure where we disagree...
I like them there, but they do introduce questions about usage. In particular, you need to leave "kind" because as far as I see, it is the only way to get the tag identity of a signature.
You should not use it directly in 99% of all cases and use
is_function_kind<Tag, T>
Hmmm. I do not see this anywhere in the online documentation.
<CITE> template<typename Tag, typename T> struct is_function_type; </CITE> In fact it's in there two times ;-).
instead. Actually there are no public functions to properly compare the tags so you should stay away from this.
Actually, I was thinking of something more along the line of...
is_function_type< function_type_signature< foo_t >::kind, bar_t >::value
though function_kind would be nicer...
No - just simply: is_function_type<Tag,T>. There really should be a note that these members are there, because they are there and are not at all required for basic usage. It leads to too much confusion. There also should be a note that 'function_type_signature' is only needed if you need a full representation in a single type (i.e. a Sequence of sub-types with some additional properties). The "Encapsulation" section states this but I bet it could do this stronger. In most cases you won't need this class at all. Again, structuring into two sections may help.
I question the "types" because I think it could be a little easier to get the return type, and the parameters without the optional class sandwiched inbetween.
Actually it _is_ a lot easier:
function_type_signature<T>
is a model of MPL Sequence.
No need to mess with the 'types' member, unless for optimization (e.g. you want a mutable sequence and don't want dependencies to function_type.hpp).
I guess, from just reading, I do not see how you know if you should "skip" the optional "class" member of the sequence, without some sort of conditional code.
Sub-types include: result type, followed by the class type (if present) followed by parameter types. If you only want parameter types use 'function_type_parameter' (a single one) 'function_type_parameters' (all of them). If you want the result type use 'function_type_result' if you want the class use 'function_type_class'. Only if you need all at once use 'function_type_signature'. Not sure I understand you correctly, here.
The problem is that most real-world use cases do involve more of the library than just a single function, so it'll be harder to understand what a particular function does, this way.
Right. I think we are on the same page here. Leave the current examples, but add a unified, real world example as well.
On its way.
This said, I just mentioned some doubt if the novice you are (or not are, but pretending to be for the purpose of bulletproofing the documentation) has a need for this library. No intentional offense, here.
I'm not necessarily pretending, because I do not use these techniques very often. However, I am trying to read with the view of "how can the docs be improved", rather than "do the docs meet a minimum requirement."
However, you gotta try hard to truly offend me. Unfortunately, I've found that I can offend people without even trying, which is one reason I tend to stay off the radar...
I must admit I had a strange feeling about the first rather fuzzy post. However, I believe we have located quite a few concrete spots that need improvement and ideas on how to approach these issues. Thank you very much for your detailed elaboration. Regards, Tobias

On Tue, 07 Jun 2005 23:21:47 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
There is no runtime behaviour. If you violate preconditions you get an error and the library takes some effort to give you a nice one, too.
I'm glad you spent effort to make sure the error messages were meaningful. A lot of template errors require a team of CIA agents to decipher.
The "maximum standard", however, is a very subjective thing - and existing documentation of a library dealing with a similar topic may serve as an orientation.
Yup.
No. This library only models the type system. Boost.Function (and alike) should be allowed to use this library in the future (as higher-level components use lower-level components not the other way around).
However, here are two possible recipes of how a Boost.Function could be analyzed with this library:
[snip ]
Right. The upcoming versions of these libraries and of course the ones yet to come should be encouraged to use this.
I think you are suggesting that these other libraries use function_type in their implementation. I'm suggesting that function_type should provide some extra support for them (especially boost::function) evan as a separate supplemental header file.
You should not use it directly in 99% of all cases and use
is_function_kind<Tag, T>
Hmmm. I do not see this anywhere in the online documentation.
<CITE>
template<typename Tag, typename T> struct is_function_type;
</CITE>
In fact it's in there two times ;-).
Hmmm. In your first email you used is_function_kind, to which I said it was not there, to which you replied that it is surely there, than proved it by showing that is_function_type was there. Maybe the first was a typo?
instead. Actually there are no public functions to properly compare the tags so you should stay away from this.
Actually, I was thinking of something more along the line of...
is_function_type< function_type_signature< foo_t >::kind, bar_t >::value
though function_kind would be nicer...
No - just simply: is_function_type<Tag,T>.
There really should be a note that these members are there, because they are there and are not at all required for basic usage. It leads to too much confusion.
I still do not see how that gives me what I was looking for; checking to see if a function type (i.e., bar_t) is an element of the set described by the kind of another function type (i.e., the_tag_type_of_function_type<foo_t>).
In most cases you won't need this class at all. Again, structuring into two sections may help.
Sure, I think a restructuring may help in several areas.
I must admit I had a strange feeling about the first rather fuzzy post.
I try to simply say what I think, but sometimes it does not come off quite right, especially in email. I am truly sorry for giving you the strange impression. Also, I appreciate your patience in the discussion. Hopefully, I can actually find some time to look at the implementation and try some examples myself, which would allow me to provide an official review.

Jody Hagins wrote:
On Tue, 07 Jun 2005 23:21:47 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
There is no runtime behaviour. If you violate preconditions you get an error and the library takes some effort to give you a nice one, too.
I'm glad you spent effort to make sure the error messages were meaningful. A lot of template errors require a team of CIA agents to decipher.
I do not have anything against lengthy error messages, but I dislike lengthy error messages with their significant information somewhere in the middle (which is a problem when using static assertions away from where the actual problem is).
The "maximum standard", however, is a very subjective thing - and existing documentation of a library dealing with a similar topic may serve as an orientation.
Yup.
No. This library only models the type system. Boost.Function (and alike) should be allowed to use this library in the future (as higher-level components use lower-level components not the other way around).
However, here are two possible recipes of how a Boost.Function could be analyzed with this library:
[snip ]
Right. The upcoming versions of these libraries and of course the ones yet to come should be encouraged to use this.
I think you are suggesting that these other libraries use function_type in their implementation. I'm suggesting that function_type should provide some extra support for them (especially boost::function) evan as a separate supplemental header file.
I got this. Still, I think it is (by definition) and should be (in terms of abstraction) beyond the scope of this library. Especially, I have something against this kind-of "overloading" the interface. This is a good one for an example, especially because it can be done with relatively little code, IMO.
You should not use it directly in 99% of all cases and use
is_function_kind<Tag, T>
Hmmm. I do not see this anywhere in the online documentation.
<CITE>
template<typename Tag, typename T> struct is_function_type;
</CITE>
In fact it's in there two times ;-).
Hmmm. In your first email you used is_function_kind, to which I said it was not there, to which you replied that it is surely there, than proved it by showing that is_function_type was there. Maybe the first was a typo?
Shame on me ;-). Sorry for the confusion (it was called like this in earlier stages of the library).
instead. Actually there are no public functions to properly compare the tags so you should stay away from this.
Actually, I was thinking of something more along the line of...
is_function_type< function_type_signature< foo_t >::kind, bar_t >::value
though function_kind would be nicer...
No - just simply: is_function_type<Tag,T>.
There really should be a note that these members are there, because they are there and are not at all required for basic usage. It leads to too much confusion.
I still do not see how that gives me what I was looking for; checking to see if a function type (i.e., bar_t) is an element of the set described by the kind of another function type (i.e., the_tag_type_of_function_type<foo_t>).
OK - if that's what you are trying to do your code look good (in case you said this I must have overlooked it). BUT: Careful here! The Tag contained in 'function_type_signature' describes the kind of function type as detailed as possible: is_function_type< function_type_signature< void(*)() >::kind , void(*)(...) >::value evaluates to 'false', because the tag given to 'is_function_type' is: non_variadic_defaultcall_function_pointer while the tag computed from void(*)(...) is variadic_defaultcall_function_pointer which is not a subset of the above. Curious question: what's the intention behind this ?
In most cases you won't need this class at all. Again, structuring into two sections may help.
Sure, I think a restructuring may help in several areas.
I must admit I had a strange feeling about the first rather fuzzy post.
I try to simply say what I think, but sometimes it does not come off quite right, especially in email.
Never mind. I know this too well from a first-person perspective.
I am truly sorry for giving you the strange impression. Also, I appreciate your patience in the discussion.
You don't have to, as it turned out to be constructive.
Hopefully, I can actually find some time to look at the implementation and try some examples myself, which would allow me to provide an official review.
This would be great (and it's probably motivating for you to hear that the actual implementation is quite small - only about 1500 lines incl. comments but without preprocessed files). Thanks, Tobias

On Wed, 08 Jun 2005 02:39:25 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
OK - if that's what you are trying to do your code look good (in case you said this I must have overlooked it).
BUT: Careful here! The Tag contained in 'function_type_signature' describes the kind of function type as detailed as possible:
is_function_type< function_type_signature< void(*)() >::kind , void(*)(...) >::value
evaluates to 'false', because the tag given to 'is_function_type' is:
non_variadic_defaultcall_function_pointer
while the tag computed from void(*)(...) is
variadic_defaultcall_function_pointer
which is not a subset of the above.
Hmmm. Kinda like getting the most derived type when calling typeid on an instance of a polymorphic class. Interesting. I'm not sure how much I like that, but I'm not sure about the alternatives either...
Curious question: what's the intention behind this ? I dunno. I just thought it was a possible use of the interface. However, one of the thoughts was that I do not necessarily know the tag, but I have a type. Maybe something like iterating through a collection of types, looking for types that are elements of the same type-tag set, so that I can perform some action (like registering that type with some multi-signal mechanism).
One of my mottos is: "If you don't want me to do it, don't provide the interface." Around here, I am known for "breaking" code the first time I use it, because I seem to automatically see uses that were not necessarily intended... it also explains some of the reasons I am so pedantic about docs.

I'll have to answer this upside down: Jody Hagins wrote:
On Wed, 08 Jun 2005 02:39:25 +0200 One of my mottos is: "If you don't want me to do it, don't provide the interface." Around here, I am known for "breaking" code the first time I use it, because I seem to automatically see uses that were not necessarily intended... it also explains some of the reasons I am so pedantic about docs.
So I can be happy to benefit from your "quality assurance instinct" ;-). In fact, I was (and still are) unsure if the members of 'function_type_signature' should be documented at all. The primary interface for type analysis (clasification & decomposistion), is_function_type function_type_arity function_type_result function_type_class function_type_parameter* and all MPL-Sequence operations (called "Intrinsic Metafunctions" in its docs which means things as: front, back, at, ...) are built upon one single class: function_type_signature Therefore, all these members have at least an internal right to exist. I did document them "just in case", because there might be some corner-cases in which their use is more efficient or convenient. It seems safe to remove them from the documentation to me ITM, but I want to think some more about it before doing so. Another option could be to move their description to a comment in the header. If they are kept, however, I see the documentation should be changed to make a very clear recommendation not to use them, unless having good reasons.
Tobias Schwinger <tschwinger@neoscientists.org> wrote:
[...]
Hmmm. Kinda like getting the most derived type when calling typeid on an instance of a polymorphic class. Interesting. I'm not sure how much I like that, but I'm not sure about the alternatives either...
It's used internally by 'is_function_type' (to match it against the tag specified by the client) and by the Sequence operations (to reconstruct the type after the Sequence has been modified). I guess this gives you an idea why you get the "most specialized" tag.
Curious question: what's the intention behind this ?
I dunno. I just thought it was a possible use of the interface. However, one of the thoughts was that I do not necessarily know the tag, but I have a type. Maybe something like iterating through a collection of types, looking for types that are elements of the same type-tag set, so that I can perform some action (like registering that type with some multi-signal mechanism).
OK, let's say we want to register a whole bunch of functions. This implies that we are either using Fusion-tuples (or alike) or pointer (to member) non-type template parameters, because the type of a pointer (or reference) is not enough to describe a function we can call. For sorting, a custom comparator gives you the flexibilty to define whatever ordering you like. A simple scenario could be something like this: A vector of tags for the groups and a binary metafunction that compares the index of the first match (found by applying is_function_type) in this vector for each parameter as the comparator. However, if your only criterium for sorting is the type-tag you might be better off with filtering, anyway. In fact, I'm not convinced that sorting is appropriate here at all: it seems to me like a case for making decisions inside the iteration on a per-function basis on which runtime code, dispatch identifier, map entry, etc. to use (and make sure similar functions end up in the same pot, somehow ;-) ). Generally, I believe there are still lots of interesting design opportunities in the direction of "intelligent callbacks facilities" (and the library we're talking about here is another puzzle piece for their implementation). Thanks again for spending so much time evaluating my submission. Regards, Tobias

On Wed, 08 Jun 2005 16:06:17 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
I did document them "just in case", because there might be some corner-cases in which their use is more efficient or convenient. It seems safe to remove them from the documentation to me ITM, but I want to think some more about it before doing so. Another option could be to move their description to a comment in the header.
If they are kept, however, I see the documentation should be changed to make a very clear recommendation not to use them, unless having good reasons.
I think the question is not of whether they should be documented, but whether they should be exposed. If they are exposed, then they should be documented. If you do not want them to be used, then protect them, or put them in the detail namespace. On what is necessary to leave as a viable user interface, only use will really tell. I have found it much easier to broaden a restricted interface than the inverse (mostly because once you provide the interface, someone is bound to use it, if for no other reason than it exists).

Jody Hagins wrote:
On Wed, 08 Jun 2005 16:06:17 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
I did document them "just in case", because there might be some corner-cases in which their use is more efficient or convenient. It seems safe to remove them from the documentation to me ITM, but I want to think some more about it before doing so. Another option could be to move their description to a comment in the header.
If they are kept, however, I see the documentation should be changed to make a very clear recommendation not to use them, unless having good reasons.
I think the question is not of whether they should be documented, but whether they should be exposed. If they are exposed, then they should be documented. If you do not want them to be used, then protect them, or put them in the detail namespace.
I can't really say: "I want noone to use this", here. All I can say is "do not use unless you're sure you need it". I've added a note to the documentation that this class is a "white box", however. Regards, Tobias

Tobias Schwinger wrote:
However, here are two possible recipes of how a Boost.Function could be analyzed with this library:
1. AFAIK Boost.Function uses a non-templated parentheses operator therefore you can apply a typeof operator (or Boost.Typeof) on a pointer to its operator() function (you can do this for any functor with a non-template operator()).
2.a. The "preferred syntax" is a template parametrized with a (plain) function type to describe its signature. Partial specialization or overloading can be used to get this template argument from an instantiation of 'boost::function'.
2.b. The "compatible syntax" is a template parametrized with the sub-types of its signature. There is an (even documented) "corner-case-feature" of 'function_type_signature' that allows you to grab the argument list from a class template instantiation. Because of
^^^^ This feature has been removed ! But it doesn't hurt here because: - Possibiliy No.1 is the easier and better way to go - It is unlikely that it would work on compilers where the "compatible syntax" of Boost.Function is required.
this 'boost::functionN' is a valid signature for 'function_type' (given that 'function_type_signature.hpp' is included) together with the tag 'plain_function' to get the same type that a (preferred-syntax) 'boost::function' is instantiated with.

Tobias Schwinger wrote:
Boost.Function uses a non-templated parentheses operator therefore you can apply a typeof operator (or Boost.Typeof) on a pointer to its operator() function (you can do this for any functor with a non-template operator()).
A similar technique is used in the "interpreter" example (see announcement about the update for links), except that no typeof operator is required, because this logic resides in the context of a function template (and template argument deduction can be used).

Jody Hagins wrote:
On Mon, 06 Jun 2005 22:37:06 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
BCC is broken for all sorts of reasons. It is _not_ supported and does _not_ speak enough ISO-C++. Btw. I know a workaround for the problem regarding function references but the lack of partial specialization for member function pointers is much worse.
Good news: I just found out this _can_ be worked around, so there can be full support for BCC without the need for typeof (emulation)! Not sure I get it done in the next version already, though.
However, BCB is used by a number of boosters, ...
...finding workarounds ;-) ?? Regards, Tobias

Instructions on unpacking, and running the tests/examples would be nice to have for each library being reviewed. Actually, some docs on running stuff from individual directories would be nice, since I always seem to get it wrong. The build docs suggest using a builddir, but when running bjam NOT from the top-level directory, I seem to have a very difficult time getting things to build properly. I am fairly comfortable with building boost. However, anytime I have to delve into the specific directories, I find that the builds are VERY different from invoking bjam in the top directory, especially when using the builddir and stagedir commands from the top level directory.

Jody Hagins <jody-boost-011304@atdesk.com> writes:
Instructions on unpacking, and running the tests/examples would be nice to have for each library being reviewed.
There's no need to repeat these instructions for each individual library. It's essentially the same procedure for each of them. The problem is that we have a pretty installation interface at the top-level that's a wrapper over the slightly uglier interface that BBv1 uses most of the time, and it doesn't apply lower down.
Actually, some docs on running stuff from individual directories would be nice, since I always seem to get it wrong. The build docs suggest using a builddir,
What's a builddir?
but when running bjam NOT from the top-level directory, I seem to have a very difficult time getting things to build properly.
Can you give some clues as to what problems you have?
I am fairly comfortable with building boost. However, anytime I have to delve into the specific directories, I find that the builds are VERY different from invoking bjam in the top directory, especially when using the builddir and stagedir commands from the top level directory.
There are no such commands anywhere else. You can set ALL_LOCATE_TARGET to point at the root directory of a build tree, if that helps. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Mon, 06 Jun 2005 12:12:04 -0400 David Abrahams <dave@boost-consulting.com> wrote:
What's a builddir?
The --builddir option to bjam, as documented in boost/more/getting_started.html
but when running bjam NOT from the top-level directory, I seem to have a very difficult time getting things to build properly.
Can you give some clues as to what problems you have?
It always wants to build and link in $BOOST_ROOT/bin/boost instead of the build directories. I build for speveral different OS/compiler versions out of the same source tree.
I am fairly comfortable with building boost. However, anytime I have to delve into the specific directories, I find that the builds are VERY different from invoking bjam in the top directory, especially when using the builddir and stagedir commands from the top level directory.
There are no such commands anywhere else.
You can set ALL_LOCATE_TARGET to point at the root directory of a build tree, if that helps.
I'll try that again. The last time I tried that one, it didn't work quite right, and I reverted back to using a separate directory and building all in the "default" location. It's funny, though, because the documentation for building boost suggests using a separate build directory, yet it seems a bit clumsy to get it to work appropriately from subdirs. Also, when a do a bjam clean from within a subdirectory, it removes the needed libraries as well. Thus, when I rebuild, it has to rebuild the test libraries too...

Compiling on gcc 3.2, I get tons of compiler warnings about volatile qualifiers on functions. Specifically, things like this... gcc-C++-action ../../../bin/boost/libs/function_types/test/variadic_function_types.tes t/gcc/debug/variadic_function_types.o /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp: In instantiation of `boost::detail::cv_traits_imp<void (*)(const char*, ...)>': /home/jody/src/Borg/HEAD/boost/boost/type_traits/remove_cv.hpp:28: instantiated from `boost::remove_cv<void ()(const char*, ...)>' /home/jody/src/Borg/HEAD/boost/libs/function_types/example/variadic_fun ction_types.cpp:28: instantiated from `boost::function_types::function_type_signature<void ()(const char*, ...)>' /home/jody/src/Borg/HEAD/boost/libs/function_types/example/variadic_fun ction_types.cpp:28: instantiated from `boost::function_types::is_function_type<boost::function_types::tags::a ny_function, void ()(const char*, ...)>' /home/jody/src/Borg/HEAD/boost/libs/function_types/example/variadic_fun ction_types.cpp:28: instantiated from `mpl_::assert_arg_pred_not<boost::function_types::is_function_type<boos t::function_types::tags::any_function, void ()(const char*, ...)> >' /home/jody/src/Borg/HEAD/boost/libs/function_types/example/variadic_fun ction_types.cpp:28: instantiated from here /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp:52: warning: ignoring `volatile' qualifiers on `void ()(const char*, ...)' /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp:53: warning: ignoring `volatile' qualifiers on `void ()(const char*, ...)' /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp:51: warning: ignoring `volatile' qualifiers on `void ()(const char*, ...)' /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp:51: warning: ignoring `volatile' qualifiers on `void ()(const char*, ...)' /home/jody/src/Borg/HEAD/boost/boost/type_traits/detail/cv_traits_impl. hpp:54: warning: ignoring `volatile' qualifiers on `void ()(const char*, ...)'

Jody Hagins wrote:
Compiling on gcc 3.2, I get tons of compiler warnings about volatile qualifiers on functions. Specifically, things like this... ...
Thanks for your report. Unfortunately I'm having difficulties to reproduce this, using gcc 3.2 (mingw32) gcc 3.3, 3.4 and gcc 4.0 (Gentoo Linux - don't have 3.2 installed on this machine). Can you tell me your platform and exact compiler version ? Regards, Tobias

On Mon, 06 Jun 2005 23:18:27 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Jody Hagins wrote:
Compiling on gcc 3.2, I get tons of compiler warnings about volatile qualifiers on functions. Specifically, things like this... ...
Thanks for your report.
Unfortunately I'm having difficulties to reproduce this, using gcc 3.2 (mingw32) gcc 3.3, 3.4 and gcc 4.0 (Gentoo Linux - don't have 3.2 installed on this machine).
Can you tell me your platform and exact compiler version ?
I simply ran bjam in the test subdirectory... shandalle:jody> cat /etc/redhat-release Red Hat Linux release 7.3 (Valhalla) shandalle:jody> uname -a Linux shandalle.atdesk.com 2.4.18-18.7.xsmp #1 SMP Wed Nov 13 19:01:42 EST 2002 i686 unknown shandalle:jody> g++ --version g++ (GCC) 3.2 Copyright (C) 2002 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Jody Hagins wrote:
On Mon, 06 Jun 2005 23:18:27 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Can you tell me your platform and exact compiler version ?
I simply ran bjam in the test subdirectory...
shandalle:jody> cat /etc/redhat-release Red Hat Linux release 7.3 (Valhalla) shandalle:jody> uname -a Linux shandalle.atdesk.com 2.4.18-18.7.xsmp #1 SMP Wed Nov 13 19:01:42 EST 2002 i686 unknown shandalle:jody> g++ --version g++ (GCC) 3.2
Strange.... Looks like I have to re-install GCC 3.2 on UNIX.

is_function_type.cpp is incomplete, as it should test that each type IS what is expected and is NOT everything else.

Jody Hagins wrote:
is_function_type.cpp
is incomplete, as it should test that each type IS what is expected and is NOT everything else.
AFAIK type categorization is about asking if an arbitrary type has some properties... I'm afraid I don't get your point, here. Can you please elaborate ? Regards, Tobias

On Mon, 06 Jun 2005 23:20:29 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Jody Hagins wrote:
is_function_type.cpp
is incomplete, as it should test that each type IS what is expected and is NOT everything else.
AFAIK type categorization is about asking if an arbitrary type has some properties...
I'm afraid I don't get your point, here. Can you please elaborate ?
Maybe I'm just being pedantic, but I think tests should be as complete as possible. I have not looked at all tests, but the one I did look at (is_function_type.cpp) seemed a bit lacking on coverage. Obviously, you think at least somewhat similarly, because you have... BOOST_MPL_ASSERT(( is_function_type<function_reference,my_function_ref> )); BOOST_MPL_ASSERT_NOT(( is_function_type<plain_function,my_function_ref> )); but you are missing several others, including some obvious ones (assuming I understand is_function_type)... BOOST_MPL_ASSERT_NOT(( is_function_type<function_pointer,my_function_ref> )); BOOST_MPL_ASSERT_NOT(( is_function_type<member_function_pointer,my_function_ref> )); I know we can not test EVERYTHING, but we should test everything that could fail, within reason.

Jody Hagins wrote:
On Mon, 06 Jun 2005 23:20:29 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Jody Hagins wrote:
is_function_type.cpp
is incomplete, as it should test that each type IS what is expected and is NOT everything else.
AFAIK type categorization is about asking if an arbitrary type has some properties...
I'm afraid I don't get your point, here. Can you please elaborate ?
Maybe I'm just being pedantic, but I think tests should be as complete as possible. I have not looked at all tests, but the one I did look at (is_function_type.cpp) seemed a bit lacking on coverage. Obviously, you think at least somewhat similarly, because you have...
Ahh - you are talking about the test. Sorry, I missed the file extension: Actually this is an "example/test hybrid" take a look at libs/function_types/test/arity_and_type.cpp This test is the output of an external code generator in the 'tools' directory and should be much more bullet proof (but this is a "real test" with no "example aspects", so I would not hyperlink it to the documentation). Regards, Tobias

On Tue, 07 Jun 2005 13:29:30 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Ahh - you are talking about the test. Sorry, I missed the file extension:
Actually this is an "example/test hybrid" take a look at
libs/function_types/test/arity_and_type.cpp
This test is the output of an external code generator in the 'tools' directory and should be much more bullet proof (but this is a "real test" with no "example aspects", so I would not hyperlink it to the documentation).
OK, Thanks. Taking a brief look at arity_and_type.cpp, it seems to be missing some stuff... no tests for any_function no tests for any of the tags with variadic in the name The tests in the examples directory for those are not sufficient, and the perl script should be modified to add tests for the missing ones...

Jody Hagins wrote:
On Tue, 07 Jun 2005 13:29:30 +0200 Tobias Schwinger <tschwinger@neoscientists.org> wrote:
Ahh - you are talking about the test. Sorry, I missed the file extension:
Actually this is an "example/test hybrid" take a look at
libs/function_types/test/arity_and_type.cpp
This test is the output of an external code generator in the 'tools' directory and should be much more bullet proof (but this is a "real test" with no "example aspects", so I would not hyperlink it to the documentation).
OK, Thanks.
Taking a brief look at arity_and_type.cpp, it seems to be missing some stuff...
no tests for any_function
no tests for any of the tags with variadic in the name
The tests in the examples directory for those are not sufficient, and the perl script should be modified to add tests for the missing ones...
I agree - these should be added (there can't be enough tests, can there ?). Evaluating the sufficiency of tests, however, does AFAIK require an understanding of the implementation: Inside a system there are always certain laws that are assumed to be tautologies, such as adding 1 and 2 becomes 3. So there is no point in testing parts of an implementation that are directly based upon these laws, because there is no way to verify the result from within the system. Regards, Tobias

John Maddock wrote:
The Formal Review of the Function Types Library begins today, and runs until 16th June 2005.
Given the recent discussions about the low turnout for the typeof review, esp. since a release is still imminent, I'd like to request a longer review period. Jonathan

Jonathan Turkanis wrote:
John Maddock wrote:
The Formal Review of the Function Types Library begins today, and runs until 16th June 2005.
Given the recent discussions about the low turnout for the typeof review, esp. since a release is still imminent, I'd like to request a longer review period.
Jonathan
Makes sense to me. What does the review manager think about it ? Regards, Tobias

Given the recent discussions about the low turnout for the typeof review, esp. since a release is still imminent, I'd like to request a longer review period.
Jonathan
Makes sense to me. What does the review manager think about it ?
Fine by me, folks are a little distracted by the release at present as well, how much longer should we allow, is to the start of the following week (the 20th) long enough? John.

John Maddock wrote:
Given the recent discussions about the low turnout for the typeof review, esp. since a release is still imminent, I'd like to request a longer review period.
Jonathan
Makes sense to me. What does the review manager think about it ?
Fine by me, folks are a little distracted by the release at present as well, how much longer should we allow, is to the start of the following week (the 20th) long enough?
I know I have never given a review but I feel that a 20 day period for reviews rather than a 10 day period for reviews would give potential reviewers, like me, a more comfortable zone in which to seriously look at potential Boost software and give one. I think that would be a good compromise between the present 10 day period, which seems to quick and a full month period which seems too long.

Sorry if this duplicates any previous comments, but you get my perspective raw from the documentation, rather than following other reviews <g> I suspect I will only be able to reveiw the documentation as our production compiler is Borland, which I don't beleive is intended as a supported compiler. I find the motivation compelling enough to investigate the library, but wonder what to do about callable types that are not function types? Do we need a Callable Types library on top of function types? In partial answer to my own question, it is worth noting that a function pointer and a struct-with-overloaded-function-call-operator are VERY different beasts anyway - for instance only the struct type can be portably cast to void *, struct types may overload mulitple calling signatures, etc. Tag types: The list of tag types includes all variation of function and function pointer, but nothing for function references. Is this intentional? Given const and volatile are effectively independant dimensions, it would be nice for the tags not to require a specific ordering (i.e. const_volatile) However, apart from providing a redundant volatile_const set of typedef I have no better answer. This only starts to become a problem is the const/volatile set is expanded in a future C++ standard, so can safely be ignored for now <g> As I read on I can't help but notice the similarity with type_traits, but don't see any cross-reference in the docs. In particular, I'm wondering if the interfaces differ in any way, and whether the ultimate plan would be to submit function_types as an expansion to type_traits for library TR2? OK, that's the end of lunch-break, will try to take a deeper look this evening. AlisdairM

Hello Alisdair, Alisdair Meredith wrote:
Sorry if this duplicates any previous comments, but you get my perspective raw from the documentation, rather than following other reviews <g>
I suspect I will only be able to reveiw the documentation as our production compiler is Borland, which I don't beleive is intended as a supported compiler.
it's currently not among the supported compilers. There might be partial support in the future. Providing full support for the current version of BCB seems nearly impossible, due to the lack of partial template specialization for member function pointers. If Borland is serious about continuing "C++Builder classic", it should be time for a new version, soon (and if they fix the bug above or at least introduce a native typeof operator I'll fully support it).
I find the motivation compelling enough to investigate the library, but wonder what to do about callable types that are not function types? Do we need a Callable Types library on top of function types?
In partial answer to my own question, it is worth noting that a function pointer and a struct-with-overloaded-function-call-operator are VERY different beasts anyway - for instance only the struct type can be portably cast to void *, struct types may overload mulitple calling signatures, etc.
If we want to look at a class type with a single overload for the parentheses operator which is not a function template (like an instantiation of boost::function or STL functors) we can use this library to look at its operator() member. If we wanted to encapsulate this functionality in a metafunction we need a way to find out the type of the expression "T::operator()", which in turn requires a typeof operator or Boost.Typeof, which in turn requires registration for some compilers. If we drop the idea of putting this into a metafunction, however, we can use a function template to deduce the type of "T::operator()" instead of requiring typeof, which is by far the more attractive solution in most situations. The only problem with this technique is that it has to applied manually. One of the examples shows this technique. Then there are class types with a parentheses operator which is a function templates or multiple overloads of the operator() function: C++ does not provide a way to query this. Even worse: the technique described above will fail to compile for these kind of functors because in this case we have to know which overload or instantiation we want when creating a pointer (this applies to any overloaded or templated function) with a cast expression. If we do know which overloads are there, the synthesis part of this library can be used to create the type for such a cast expression, though.
Tag types: The list of tag types includes all variation of function and function pointer, but nothing for function references. Is this intentional?
Are you talking about the synopsis block ? Well, I had to put the "..." somewhere ;-).
Given const and volatile are effectively independant dimensions, it would be nice for the tags not to require a specific ordering (i.e. const_volatile) However, apart from providing a redundant volatile_const set of typedef I have no better answer. This only starts to become a problem is the const/volatile set is expanded in a future C++ standard, so can safely be ignored for now <g>
In fact, I'm not too sure about handling cv with the tags is the wisest choice. The const/volatile qualification of a member function can be seen as const volatile qualification on the "this-pointee", therefore it's a thinkable solution to use cv-qualification of the class type instead.
As I read on I can't help but notice the similarity with type_traits, but don't see any cross-reference in the docs. In particular, I'm wondering if the interfaces differ in any way, and whether the ultimate plan would be to submit function_types as an expansion to type_traits for library TR2?
Of course, TypeTraits deals with a similar topic and FunctionTypes can be seen as an expansion, already. I gave it an own indentity rather than trying to write a "plugin for TypeTraits" because the interfaces and dependencies of the two are too different and not to interfere with the ongoing efforts of standardisation. This library should be "officially boostified", before talking about "ultimate plans" and TR2, IMO.
OK, that's the end of lunch-break, will try to take a deeper look this evening.
Thank you, already. I'm looking forward to read more. Regards, Tobias

Tobias Schwinger wrote:
Hello Alisdair,
Alisdair Meredith wrote:
Sorry if this duplicates any previous comments, but you get my perspective raw from the documentation, rather than following other reviews <g>
I suspect I will only be able to reveiw the documentation as our production compiler is Borland, which I don't beleive is intended as a supported compiler.
it's currently not among the supported compilers.
There might be partial support in the future. Providing full support for the current version of BCB seems nearly impossible, due to the lack of partial template specialization for member function pointers.
Correction: fully supporting Borland _is_ possible ;-) (just found a workaround) although I probably won't get it done in the next version. Regards, Tobias

"John Maddock" wrote
The Formal Review of the Function Types Library begins today, and runs until 16th June 2005.
What is your evaluation of the design?
Not being a target everyday user of this library I wouldnt like to make too much comment.. OTOH ... here goes ;-) Is there a proposed use for these tags? I'm interested in the reason for use of these tags over separate functions. eg instead of .. template<typename Tag, typename T> struct is_function_type; Why not : is_any_function<F> is_variadic_function<f> etc OTOH why not do it the other way round eg template<typename F, typename Tag = any_function> struct is_function_type; eg giving is_function_type<F> for what I guess is the most usual case. I know this overlaps type_traits, but therefore is this any_function necessary? Does providing non functions-types to eg function_type_arity<F> give a compile time assertion? Cos I think it should!
What is your evaluation of the implementation?
I havent looked at the implementation.
What is your evaluation of the documentation?
I would really like an accessible example right at the start. What is this library useful for? The example source files seem to have little regard for anyone reading them. The closure example looks interesting (though I'm not sure what a closure is)but perhaps this could be the basis of an in depth example followed through in the documentation. There are few comments in the examples and in a lot of cases they just look like test programs. I'd especially like to see an example of application to callbacks. eg (Apologies I may be rambling, but I'm trying to find simple useage scenarios in the following. Of course standard library examples would be better)) Say I needed a list of actions on a list with varying arguments: I could make some Functors: // Abstract Base Class template<typename List> struct Action { virtual List & operator() (List & in)=0; // do something to a list }; // some actions -- sort template<typename List> struct MySort : Action<List>{ typedef typename List::value_type value_type; typedef bool (*pf) (value_type const & , value_type const &); MySort (pf pf_in); // construct with required function List & operator() (List & in); }; // remove on predicate template<typename List> struct RemoveIf : Action<List>{ typedef typename List::value_type value_type; typedef bool (*pf) (value_type const & ); RemoveIf (pf pf_in); // construct with required function List & operator() (List & in); }; But presumably I could replace these two derived classes by suitable use of function_traits template<typename List, typename FunctionType> struct MyAction : Action<List>{ typedef typename List::value_type value_type; typedef typename Unwrap<FunctionType>::type function; function f; List & operator()(List & in)const { // some generic mechanism to invoke on varying args invoke<FunctionType>(in,typename FunctionType::ArgType(f) ); } MyAction(function in): f(in); }; Unwrap is some magic to create the function pointer from its varying parts Wrap is some magic to construct the FunctionType from an input function type; The above may or may not make sense... Whatever there must be some more Simple useage examples. IOW how is this library useful with callbacks and/or synthesis of functions?
What is your evaluation of the potential usefulness of the library?
I think its up to the author to show me with better simpler examples, showing this.
Did you try to use the library? With what compiler? Did you have any problems?
I tried a couple of simple examples in VC7.1. No problems.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
A couple of hours thinking and reading.
Are you knowledgeable about the problem domain?
No.
And finally, every review should answer this question:
Do you think the library should be accepted as a Boost library? Be sure to say
I abstain. If its useful in implementing all the libraries it says it can then it must be very useful, but I'm afraid that the author must take more trouble with explaining things to simpler souls like myself in my opinion. regards Andy Little

Hi Andy, thank you for your review ! Andy Little wrote:
"John Maddock" wrote
The Formal Review of the Function Types Library begins today, and runs until 16th June 2005.
What is your evaluation of the design?
Not being a target everyday user of this library I wouldnt like to make too much comment.. OTOH ... here goes ;-)
Is there a proposed use for these tags? I'm interested in the reason for use of these tags over separate functions. eg instead of ..
template<typename Tag, typename T> struct is_function_type;
Why not :
is_any_function<F> is_variadic_function<f>
etc
The tags allow us to have two coordinated counterparts 'function_type' (builds function type) and 'function_type_signature' (takes a function_type apart). The tags may change with the configuration of the library and they are very lightweight. Using metafunctions instead would mean generating lots of code that is never used in most cases: There would have to be two metafunctions per tag - one for classification and one for synthesis (except for the "abstract" ones). Looking closer at the type synthesis part we would end up with lots of functions that do exactly the same thing. E.g: function_pointer<Seq> defaultcall_function_pointer<Seq> non_variadic_function_pointer<Seq> non_variadic_defaultcall_function_pointer<Seq> or we would only use the "most concrete" (the one at the bottom of the list -- I guess its name is already enough reason not to seriously consider this) or we would drop the symmetry of sythesis and decomposition (imposing a huge ammount of irregularity on the user).
OTOH why not do it the other way round eg
template<typename F, typename Tag = any_function> struct is_function_type;
I found it appealing to have the tag next to ("extend") the identifier.
eg giving is_function_type<F> for what I guess is the most usual case.
Don't think so. I don't see a reasonable default, here.
I know this overlaps type_traits, but therefore is this any_function necessary?
In fact, this particular case doesn't (at least not exactly), but it can be modeled with TypeTraits, if this is what you mean. It will look somewhat like this (untested freehand code): mpl::or_< is_function< typename remove_reference<typename remove_pointer<T>::type>::type > , is_member_function_pointer<T> >
Does providing non functions-types to eg function_type_arity<F> give a compile time assertion? Cos I think it should!
It gives you a compile error at the point you try to access '::value' ("function_type_arity<Blah blah blah> does not have a member named value"). 'BOOST_STATIC_ASSERT' or 'BOOST_MPL_ASSERT*' are not used for this, because this would trigger an error inside the library, instead of where the actual problem in client code is. IIRC using this technique was inspited by TypeTraits.
What is your evaluation of the implementation?
I havent looked at the implementation.
What is your evaluation of the documentation?
I would really like an accessible example right at the start. What is this library useful for? The example source files seem to have little regard for anyone reading them.
You're right - it's missing.
The closure example looks interesting (though I'm not sure what a closure is) but ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There is a brief introduction in the header, if it doesn't work for you, try Wikipedia or alike.
perhaps this could be the basis of an in depth example followed through in the documentation. There are few comments in the examples and in a lot of cases they just look like test programs.
There should be something like this. I'm not sure if I want to use one of the in-depth examples (they are probably too far out for the docs) or smaller but still "real ones", though. I think per-function examples are important, too. And I can try to come up with some less boring ones...
I'd especially like to see an example of application to callbacks.
Well, the closure example shows a special case of "callback" (partial argument binding). Another, more general example in this direction has been recently added to the library: - interpreter.hpp [ http://tinyurl.com/bu5vn ] - interpreter_example.cpp [ http://tinyurl.com/8ryt3 ]
eg (Apologies I may be rambling, but I'm trying to find simple useage scenarios in the following. Of course standard library examples would be better))
[...]
Let me ramble too and try an STL-style version (and I'll substitute 'remove_if' from your example with 'partition' - because I find it just too weird, otherwise. It's still odd enough, I guess). template<std::size_t Arity> struct sort_somehow_impl; // Sorts or partitions the data in the range [from;to) for unary or binary // predicate functions respectively template<typename Iterator, typename Function> void sort_somehow(Iterator const & from, Iterator const & to, Function f) { sort_somehow_impl< ::boost::function_type_arity<Function>::value > ::work(from,to,f); } template<> struct sort_somehow_impl<1> { template<typename Iterator, typename Function> static void work(Iterator const & from, Iterator const & to, Function f) { std::stable_partition(from,to,f); } }; template<> struct sort_somehow_impl<2> { template<typename Iterator, typename Function> static void work(Iterator const & from, Iterator const & to, Function f) { std::stable_sort(from,to,f); } }; When the function template 'sort_somehow' is instantiated it will generate a body that either invokes 'std::stable_partition' or 'std::stable_sort' depending on the arity of the passed function pointer or -reference. Since it's an STL-style example we might want to add support for STL-style functors: In my reply to Alisdair Meredith's comments I explained why you would need to depend on typeof if you wanted to provide an interface similar to the one of this library for simple functors. However, the arity is a special case because it's numeric. We _can_ write a generalized metafunction that works on both function types and simple functors: // This one knows the type of the member function pointer expression // and can return the arity encoded in the size of a char array reference. template<typename MemFnPtr> char (& simple_functor_arity_impl(MemFnPtr)) [ ::boost::function_type_arity<MemFnPtr>::value + 1 ]; // Uses the sizeof operator to decode the arity from the result of the // function template declared above when used with the expression // '& F::operator()'. template<typename F> struct simple_functor_arity : boost::mpl::size_t < sizeof(simple_functor_arity_impl(&F::operator())) - 1 > { }; // Wrapper for 'function_type_arity' which will try to inspect the type // of the expression '& F::operator()' instead of F, if F is not a // function type. template<typename F> struct function_or_functor_arity : boost::mpl::if_< boost::is_function_type<boost::any_function, F> , boost::function_type_arity<F> , simple_functor_arity<F> >::type { }; Now the only thing left to do is replace this line ::boost::function_type_arity<Function>::value from our first attempt with ::function_or_functor_arity<Function>::value and maybe add this comment: // ATTENTION: this will not work for function objects with a // parentheses operator which is a function template or an // overloaded function to make our example work with simple functors. Here is a skeleton to reproduce it with a compiler (all code has been tested with GCC 3.4): #include <cstddef> #include <algorithm> #include <functional> #include <iostream> #include <boost/mpl/if.hpp> #include <boost/mpl/size_t.hpp> #include <boost/function_types/is_function_type.hpp> #include <boost/function_types/function_type_arity.hpp> // <--- the code discussed above comes here int main() { static const std::size_t n = 10; int e[] = { 5,0,2,0,7,0,8,1,12,1 }; sort_somehow((int*)e, e+n, std::logical_not<int>()); for (int i = 0; i < n; ++i) std::cout << e[i] << " "; std::cout << std::endl; // output: 0 0 0 5 2 7 8 1 12 1 sort_somehow((int*)e, e+n, std::less<int>()); for (int i = 0; i < n; ++i) std::cout << e[i] << " "; std::cout << std::endl; // output: 0 0 0 1 1 2 5 7 8 12 return 0; }
What is your evaluation of the potential usefulness of the library?
I think its up to the author to show me with better simpler examples, showing this.
Did you try to use the library? With what compiler? Did you have any problems?
I tried a couple of simple examples in VC7.1. No problems.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
A couple of hours thinking and reading.
Are you knowledgeable about the problem domain?
No.
And finally, every review should answer this question:
Do you think the library should be accepted as a Boost library? Be sure to say
I abstain. If its useful in implementing all the libraries it says it can then it must be very useful, but I'm afraid that the author must take more trouble
David Abrahams suggested to apply this library to existing Boost code as a proof of concept. I'm currently working on it.
with explaining things to simpler souls like myself in my opinion.
Writing documentation, especially good documentation understood by a wide audience, is not an easy task. I honestly hope I am not too simple of a soul to succeed in making the next revision more understandable. Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d8q4ch$dp7$1@sea.gmane.org...
Hi Andy,
thank you for your review !
No problem. Sorry I'm not more of an expert on this :-) [snip]
Looking closer at the type synthesis part we would end up with lots of functions that do exactly the same thing. E.g:
function_pointer<Seq> defaultcall_function_pointer<Seq> non_variadic_function_pointer<Seq> non_variadic_defaultcall_function_pointer<Seq>
or we would only use the "most concrete" (the one at the bottom of the list -- I guess its name is already enough reason not to seriously consider this) or we would drop the symmetry of sythesis and decomposition (imposing a huge ammount of irregularity on the user).
Ok.
OTOH why not do it the other way round eg
template<typename F, typename Tag = any_function> struct is_function_type;
I found it appealing to have the tag next to ("extend") the identifier.
I prefer the 'policy' at the end ... whatever.
eg giving is_function_type<F> for what I guess is the most usual case.
Don't think so. I don't see a reasonable default, here.
I know this overlaps type_traits, but therefore is this any_function necessary?
In fact, this particular case doesn't (at least not exactly), but it can be modeled with TypeTraits, if this is what you mean. It will look somewhat like this (untested freehand code):
mpl::or_< is_function< typename remove_reference<typename remove_pointer<T>::type>::type > , is_member_function_pointer<T> >
OK...something else to mention in the documentation IMO. Would be nice to show relation.
Does providing non functions-types to eg function_type_arity<F> give a compile time assertion? Cos I think it should!
It gives you a compile error at the point you try to access '::value' ("function_type_arity<Blah blah blah> does not have a member named value").
'BOOST_STATIC_ASSERT' or 'BOOST_MPL_ASSERT*' are not used for this, because this would trigger an error inside the library, instead of where the actual problem in client code is.
Ok .. hmmm.... I reckon compiler error messages are output upside down. They make it easy for the libarray author, rather than the user. A switch to print error messages in reverse order would be nice :-)
I would really like an accessible example right at the start. What is this library useful for? The example source files seem to have little regard for anyone reading them.
You're right - it's missing.
Yes and something regarding decomposing a function and then doing the reverse ...synthesising it (if thats the correct use of 'synthesis') from the decomposed bits.
The closure example looks interesting (though I'm not sure what a closure is) but ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There is a brief introduction in the header, if it doesn't work for you, try Wikipedia or alike.
Ok I guess it would make sense if I found a use for it ;-) OTOH I have been mucking about with the library, because I'm sure there are uses.(I may be reinventing the wheel. If so sorry); In attached file( for no concrete purpose ) I tried to 'normalise' functions of arbitrary args into a function taking a tuple of args. Though I dont know much about Functional Programming this feels like the type of thing that might be useful.. quiz the arguments to see if their functions with a tuple of args etc, though quite how you would proceed with that I dont know.
Another, more general example in this direction has been recently added to the library:
- interpreter.hpp [ http://tinyurl.com/bu5vn ]
- interpreter_example.cpp [ http://tinyurl.com/8ryt3 ]
Whoa ... This is too complicated. Can you not just isolate the function_types part? regards Andy Little

Hi Andy, Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d8q4ch$dp7$1@sea.gmane.org...
Hi Andy,
thank you for your review !
No problem. Sorry I'm not more of an expert on this :-)
[snip]
Looking closer at the type synthesis part we would end up with lots of functions that do exactly the same thing. E.g:
function_pointer<Seq> defaultcall_function_pointer<Seq> non_variadic_function_pointer<Seq> non_variadic_defaultcall_function_pointer<Seq>
or we would only use the "most concrete" (the one at the bottom of the list -- I guess its name is already enough reason not to seriously consider this) or we would drop the symmetry of sythesis and decomposition (imposing a huge ammount of irregularity on the user).
Ok.
OTOH why not do it the other way round eg
template<typename F, typename Tag = any_function> struct is_function_type;
I found it appealing to have the tag next to ("extend") the identifier.
I prefer the 'policy' at the end ... whatever.
eg giving is_function_type<F> for what I guess is the most usual case.
Don't think so. I don't see a reasonable default, here.
I know this overlaps type_traits, but therefore is this any_function necessary?
In fact, this particular case doesn't (at least not exactly), but it can be modeled with TypeTraits, if this is what you mean. It will look somewhat like this (untested freehand code):
mpl::or_< is_function< typename remove_reference<typename remove_pointer<T>::type>::type > , is_member_function_pointer<T> >
OK...something else to mention in the documentation IMO. Would be nice to show relation.
Good one!
Does providing non functions-types to eg function_type_arity<F> give a compile time assertion? Cos I think it should!
It gives you a compile error at the point you try to access '::value' ("function_type_arity<Blah blah blah> does not have a member named value").
'BOOST_STATIC_ASSERT' or 'BOOST_MPL_ASSERT*' are not used for this, because this would trigger an error inside the library, instead of where the actual problem in client code is.
Ok .. hmmm.... I reckon compiler error messages are output upside down.
Depends on how you look at it...
They make it easy for the libarray author, rather than the user. A switch to print error messages in reverse order would be nice :-)
There is usually a trace from the point of the error to the outermost template instantiation. You'ld need a "one-before-the-innermost-switch", here ;-).
I would really like an accessible example right at the start. What is this library useful for? The example source files seem to have little regard for anyone reading them.
You're right - it's missing.
Yes and something regarding decomposing a function and then doing the reverse ...synthesising it (if thats the correct use of 'synthesis') from the decomposed bits.
The closure example looks interesting (though I'm not sure what a closure is) but
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There is a brief introduction in the header, if it doesn't work for you, try Wikipedia or alike.
Ok I guess it would make sense if I found a use for it ;-)
The designers at Borland, however found a use. So much, in fact, that they added a non-standard compiler extension for it (and the compatiblity with Delphi, I believe). C++Builder attaches event handlers to GUI components, this way. The example is pretty much modeled after these non-standard types understood by BCC.
- interpreter.hpp [ http://tinyurl.com/bu5vn ]
- interpreter_example.cpp [ http://tinyurl.com/8ryt3 ]
Whoa ... This is too complicated. Can you not just isolate the function_types part?
The number of lines may be scaring. But hey, cheer up - most of them are comments and good old runtime code ;-). Seriously, I'ld like to leave this as-is and add more simpler ones (especially as simple as a few lines - for the documentation). Contributions are welcome, of course.
// struct to 'normalise' a function: takes a tuple of args // rather than the args directly
Sorry to disappoint you, but this might be less exciting than you had hoped. (Un)fortunately there is (AFAIK) no way to get the size of a boost::tuple at compile time. So we'll use the arity of the function instead (which is worse because we could handle default arguments, otherwise). To not only use the library for a workaround here, I'll add a static assertion to restrict it to function pointers ;-). Untested code ahead, but it should be easy enough for my typos to be fixable (hope it works for you)... template<std::size_t N> struct function_feeder; template<> struct function_feeder<0> { template<class Function, class Tuple> static void feed(Function f, Tuple&) { f(); } }; template<> struct function_feeder<1> { template<class Function, class Tuple> static void feed(Function f, Tuple& t) { f(get<0>(t)); } }; template<> struct function_feeder<2> { template<class Function, class Tuple> static void feed(Function f, Tuple& t) { f(get<0>(t),get<1>(t)); } }; //... template<class Function, class Tuple> void feed_function(Function f, Tuple& t) { BOOST_STATIC_ASSERT(( ::boost::is_function_type<function_pointer,Function>::value )); function_feeder< ::boost::function_type_arity<Function>::value > ::feed(f,t); } // TODO: make compile, extend at will Thanks, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
To not only use the library for a workaround here, I'll add a static assertion to restrict it to function pointers ;-).
Untested code ahead, but it should be easy enough for my typos to be fixable (hope it works for you)...
Had some fun playing around with it some more Note that the feed_function doesnt check the arity ( or number of elements) of the tuple. However may be this could be useful. Perhaps one could add a range parameter specifying which range of args in the tuple to use. IMO Its daft that there are traits for variables and not traits for functions, which this library addresses. I reckon that there are many potential uses of this library, especially in FP style programming. Perhaps this library will help to open them up. FWIW I change my vote. I vote to accept the library into boost. regards Andy Little

Andy Little wrote:
Note that the feed_function doesnt check the arity ( or number of elements) of
^^^ Is there a way to do this with Boost.Tuple ? If there is I was too blind to find it reading the docs and taking a brief look at its source...
the tuple. However may be this could be useful. Perhaps one could add a range parameter specifying which range of args in the tuple to use.
Boost.Tuple is a very basic tuples implementation. Fusion (which is still work in progress and lives in the spirit folder) is way more flexibile (for this particular case you can define a view from a pair of iterators).
IMO Its daft that there are traits for variables and not traits for functions, which this library addresses. I reckon that there are many potential uses of this library, especially in FP style programming. Perhaps this library will help to open them up.
FWIW I change my vote. I vote to accept the library into boost.
Great! And thanks for your ideas & code! Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d91b7f$mik$2@sea.gmane.org...
Andy Little wrote:
Note that the feed_function doesnt check the arity ( or number of elements) of
^^^ Is there a way to do this with Boost.Tuple ? If there is I was too blind to find it reading the docs and taking a brief look at its source...
boost::tuples::length<Tuple>::value I think. FWIW Its first in the advanced section of the docs. regards Andy Little

Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:d91b7f$mik$2@sea.gmane.org...
Andy Little wrote:
Note that the feed_function doesnt check the arity ( or number of elements) of
^^^ Is there a way to do this with Boost.Tuple ? If there is I was too blind to find it reading the docs and taking a brief look at its source...
boost::tuples::length<Tuple>::value I think. FWIW Its first in the advanced section of the docs.
Ah - thanks! We'll want to use this instead of function_type_arity, so default arguments work. Adding an assertion that the arity of the function is greater or equal to the number of elements in the tuple would be nice. Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Ah - thanks! We'll want to use this instead of function_type_arity, so default arguments work. Adding an assertion that the arity of the function is greater or equal to the number of elements in the tuple would be nice.
Unfortunately because its a pointer to a function it wont handle the default args, at least not in my test above. (OTOH this sounds reasonably sensible) Need to swap equal_to with greater_equal in attached to try this. regards Andy Little

Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Ah - thanks! We'll want to use this instead of function_type_arity, so default arguments work. Adding an assertion that the arity of the function is greater or equal to the number of elements in the tuple would be nice.
Unfortunately because its a pointer to a function it wont handle the default args, at least not in my test above. (OTOH this sounds reasonably sensible)
<WHUMMM>Stupid me</WHUMM> Of course! I'm sorry. It seems I'm doing too much things simultanously at present... Regards, Tobias

Tobias Schwinger wrote:
Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Ah - thanks! We'll want to use this instead of function_type_arity, so default arguments work. Adding an assertion that the arity of the function is greater or equal to the number of elements in the tuple would be nice.
Unfortunately because its a pointer to a function it wont handle the default args, at least not in my test above. (OTOH this sounds reasonably sensible)
<WHUMMM>Stupid me</WHUMM>
Of course!
You can, however, check if it's a variadic function pointer and in this call allow any number of tuple elements.... Regards, Tobias

Hi Andy, sorry for spotting it this late: Andy Little wrote:
typename boost::enable_if< ::boost::is_function_type<boost::function_pointer,Function>, typename boost::function_type_result<Function>::type
^^^^ This does not really make sense because you instantiate 'function_type_result' regardless if 'Function' is a function type. Need 'lazy_enable_if' here.
::type feed_function(Function f, Tuple& t) { return function_feeder<Function>::feed(f,t); }
Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote i
Hi Andy,
sorry for spotting it this late:
Andy Little wrote:
typename boost::enable_if< ::boost::is_function_type<boost::function_pointer,Function>, typename boost::function_type_result<Function>::type
^^^^ This does not really make sense because you instantiate 'function_type_result' regardless if 'Function' is a function type. Need 'lazy_enable_if' here.
::type feed_function(Function f, Tuple& t) { return function_feeder<Function>::feed(f,t); }
Good point. Might be nice to document that as I guess that this is a common use. OTOH I guess that the fact that there iasnt a::type if its not a function is documented Another weakness of feed_function is that it doesnt support overloaded functions by deduction. regards Andy Little

Andy Little wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote i
Hi Andy,
sorry for spotting it this late:
Andy Little wrote:
typename boost::enable_if< ::boost::is_function_type<boost::function_pointer,Function>, typename boost::function_type_result<Function>::type
^^^^ This does not really make sense because you instantiate 'function_type_result' regardless if 'Function' is a function type. Need 'lazy_enable_if' here.
::type feed_function(Function f, Tuple& t) { return function_feeder<Function>::feed(f,t); }
Good point. Might be nice to document that as I guess that this is a common
In fact it gives a nice example snippet to be inlined in the docs ;-).
use. OTOH I guess that the fact that there iasnt a::type if its not a function is documented
Not that explicitly (the preconditions are listed) but it is on my list already because this question was asked too often in the review. Regards, Tobias

John Maddock wrote:
The Formal Review of the Function Types Library begins today, and runs until 16th June 2005.
Author: Tobias Schwinger tschwinger@neoscientists.org
Available from the sandbox at: http://boost-sandbox.sourceforge.net/vault/ or the zip file is:
This library provides a metaprogramming facility to classify, decompose and synthesize function-, function pointer-, function reference- and member function pointer types. For the purpose of this documentation, these types are collectively referred to as function types (this differs from the standard definition and redefines the term from a programmer's perspective to refer to the most common types that involve functions).
The classes introduced by this library shall conform to the concepts of the Boost Metaprogramming library (MPL).
The Function Types library enables the user to: * test an arbitrary type for being a function type of specified kind, * inspect properties of function types, * view and modify sub types of an encapsulated function type with MPL Sequence operations, and * synthesize function types.
This library supports variadic functions and can be configured to support non-default calling conventions.
(The following is taken from : http://www.boost.org/more/formal_review_process.htm )
Here are some questions you might want to answer in your review:
What is your evaluation of the design? What is your evaluation of the implementation? What is your evaluation of the documentation? What is your evaluation of the potential usefulness of the library? Did you try to use the library? With what compiler? Did you have any problems? How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? Are you knowledgeable about the problem domain?
And finally, every review should answer this question:
Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
John Maddock (Function Types review manager).
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Mon, 6 Jun 2005 13:53:32 +0100 "John Maddock" <john@johnmaddock.co.uk> wrote:
What is your evaluation of the design?
It seems fairly representative of current meta template programming techniques. I still have concerns about the tag-types bastraction. However, I also see the advantages. Maybe BOTH style interfaces should be provided, even though it is largely redundant. Normally redundant interfaces are a bad thing, but I'm on the fence here... I like the similarities with TypeTraits, and I sample usage has been pretty easy (once I got past my initial problems).
What is your evaluation of the implementation?
N/A.
What is your evaluation of the documentation?
As obvious from my previous comments in this thread, the documentation need a lot of work. In addition, I think a single example, developed throught the documentation would be helpful. A modified version includes better examples, but the examples need to be fully explained with lots of textual explanation (more than currently exists).
What is your evaluation of the potential usefulness of the library?
I think it can be very useful, bth for unifying the implementations of several Boost libraries and also as a good generic programming tool.
Did you try to use the library? With what compiler? Did you have any
problems?
Yes. gcc 3.2, 3.2.2. I ran into some compiler warnings, but I found that they were due to an existing bug in the gcc 3.2 compiler.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
My initial reading of the documentation was fairly quick, but I then spent some time re-reading it, and a fair amount of time in a discussion with the author. I compiled the examples and ran the tests. In addition, I tried to write some other code to use the interface, but ran out of time, and never got it working.
Are you knowledgeable about the problem domain?
Somewhat, but not near as much as some others on this list.
And finally, every review should answer this question:
Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall
opinion.
Yes, though I would regret that vote if the documentation and examples were not given a thorough re-working, taking into account all the current feedback (and applying that feedback, pretty much all of which would make the documentation much better, and the library more useful).

Hi Jody, Jody Hagins wrote:
On Mon, 6 Jun 2005 13:53:32 +0100 "John Maddock" <john@johnmaddock.co.uk> wrote:
What is your evaluation of the design?
It seems fairly representative of current meta template programming techniques. I still have concerns about the tag-types bastraction. However, I also see the advantages. Maybe BOTH style interfaces should be provided, even though it is largely redundant. Normally redundant interfaces are a bad thing, but I'm on the fence here...
This has been brought up by several reviewers, now. I've come to the conclusion that some common cases available as unary traits classes (e.g. 'is_function_pointer') are indeed helpful. I'm also thinking about introducing more orthogonality in the tag logic (inspired by Jonathan Turkanis' proposal) to increase its usability (and explainability, for that matter). I'll post a draft, later today.
What is your evaluation of the documentation?
As obvious from my previous comments in this thread, the documentation need a lot of work. In addition, I think a single example, developed throught the documentation would be helpful. A modified version includes better examples, but the examples need to be fully explained with lots of textual explanation (more than currently exists).
<snip>
Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall
opinion.
Yes, though I would regret that vote if the documentation and examples were not given a thorough re-working, taking into account all the current feedback (and applying that feedback, pretty much all of which would make the documentation much better, and the library more useful).
The docs will be reworked with most suggestions applied and a tutorial will be added. Thank you for your review and for the positive vote! Regards, Tobias
participants (9)
-
Alisdair Meredith
-
Andy Little
-
Arkadiy Vertleyb
-
David Abrahams
-
Edward Diener
-
Jody Hagins
-
John Maddock
-
Jonathan Turkanis
-
Tobias Schwinger