[Boost.Parameter] questions and advice

Boost, I've been working on parts of the Boost.Graph library as part of my Google Summer of Code project. Part of this has been implementing some new algorithms. Jeremy Siek (mentor) and I had briefly discussed using the new Boost.Parameter library instead of the older BGL Named Params solution for building the interfaces to these new algorithms. In fact, we had also talked about the possibility of migrating existing algorithms to use that style. So... after some initial experimentation, I've come up with some questions. I've just finished reading most of the original reviews for Boost.Parameter library. They weren't that helpful. 1. It seems to me that functions with named parameters are limited to 5 parameters (both required and optional) - at least under GCC 4.1.2. Is this right? If I try to add a 6th, I get a number of compiler errors of the form "6 arguments given (5 expected)" and so forth. Maybe I need to build these explicitly and avoid the macros. There are a number of algorithms in Boost.Graph for which this would be a showstopper. 2. I've run into the situation where parameters are truly optional - they don't specify default values, but optional components to an algorithm. What's the best way to implement this? How can I test (within a function) to determine if a parameter has been passed or not? I've hacked together an approach using a `not_given` struct. Is there something already like this in the library. 3. And the big kind of fuzzy question: Is there any general documented advice on building procedural interfaces with numerous default and replaceable arguments? These are all related to interface design and, if anybody responds, might generate some interesting discussion. Specific questions: - At what point should an interface consider migrating to a named parameter solution instead of providing overloads?. For example, I could probably write many of my algorithms using overloads, but in order to be consistent with Boost.Graph (and other reasons) I'd like to use Boost.Parameter. - Which is better: executing behavior based on type or value parameters and when would each be appropriate? For example, should I pass a bool or enum flag to the function and make decisions at runtime, or should I define some policy- or tag-style structs and use template instantiation to determine behavior at compile time? - What's the best way to document these interfaces. Aside from Boost.Graph, I haven't yet seen any libraries, but those are documented for BGL named params. How do you describe the signature of a function that's declared as a macro? Any thoughts at all == very much appreciated. Thanks, Andrew Sutton asutton@cs.kent.edu

On Jul 10, 2007, at 9:02 AM, Cédric Venet wrote:
I had previously considered that as an option (no pun). Unfortunately, I don't think this helps if I choose to adopt a compile-time function selection. Otherwise, it would work very nicely at runtime. I've still got it on my short list of solutions. Thanks, Andrew Sutton asutton@cs.kent.edu

From: Andrew Sutton
I'm not clear what your "truly optional" parameters are actually for, but if (for example) they supply a functor could the default value be some sort of identity functor? -- Martin Bonner Project Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

I guess it might be worthwhile to distinguish formally between optional parameters and those with default values. A parameter with default values is still a required input to a function even if the user doesn't explicitly pass a corresponding value. It's value is supplied by the specification. An optional parameter is one affects the function's behavior by its absence or presence in the argument list. There are actually a number of examples in Boost.Graph. Consider dijkstra_shortest_paths(). There are two optional (output) parameters that can be passed - a predecessor map that records the parents in the shortest path tree and a distance map that records the distance to each vertex. If they aren't supplied the algorithm doesn't do any extra work. If one or both is supplied, the algorithm records parents and/or distances. This isn't an extreme example of affected behavior, but it is probably the most common. The idea of using functors is interesting... but for some reason, I'm having trouble seeing how the solution would work this morning. I'll have to give it some thought. I think, however, that I'm doing something similar with my `not_given` type - it's being used as a sort of token that, when passed to template functions doesn't do anything. Thanks, Andrew Sutton asutton@cs.kent.edu

Quoting Andrew Sutton <asutton@cs.kent.edu>:
did you read: http://www.boost.org/libs/parameter/doc/html/index.html#optional-parameters http://www.boost.org/libs/parameter/doc/html/index.html#signature-matching-a... it does what I was trying to explain in my previous mail automaticaly and should correspond to your need (optionnal parameter and compile time function dispatching).

From: Andrew Sutton
Aahh. Light dawns.
The idea of using functors is interesting... but for some reason, I'm having trouble seeing how the solution would work this morning.
That's because I was thinking of something like "copy from here to there, optionally transforming the copied values", where a default of template <class T> T& identity(T& x) { return x; } would be fine (modulo dangling references). I'm sure someone will be along shortly to show how to do it :-)
-- Martin Bonner Project Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

on Tue Jul 10 2007, Andrew Sutton <asutton-AT-cs.kent.edu> wrote:
In that particular case I would make the defaults for those parameters be stubs that satisfy the syntactic concept requirements but on which the "recording" operations compile away to nothing. In general, I would try hard to end up with one very generic algorithm operating on parts that may or may not do anything. In cases where it's impossible to share the same code without loss of efficiency, I would use something like "tag dispatching" to choose among different implementations. It would be easy enough to dispatch on boost::parameter::void_, for example. HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

Quoting Andrew Sutton <asutton@cs.kent.edu>:
first, doing compile time dipatching is only usefull if your function is very short and the additionnal function call time is relevant (I don't think it is the case for you). If you really want a compile time dispatch, you can try to use mpl in order to find out if the parameter is in the ArgumentPack and dispatch on the result. from the doc: """ An ArgumentPack is a collection of tagged references to the actual arguments passed to a function. Every ArgumentPack is also a valid MPL Forward Sequence consisting of the keyword tag types in its tagged references. """ so it shouldn't be to hard to do. But you trade compile time versus runtime (and the runtime loss of dynamique dispatch is pretty low). for your other question: """ 7 Configuration Macros 7.1 BOOST_PARAMETER_MAX_ARITY Determines the maximum number of arguments supported by the library. Will only be #defined by the library if it is not already #defined. Defined in: boost/parameter/config.hpp Default Value: 5 """ so you can easily augment this (at the cost of some compile time probably) doc link => http://www.boost.org/libs/parameter/doc/html/reference.html

on Tue Jul 10 2007, Andrew Sutton <asutton-AT-cs.kent.edu> wrote:
Hmm, too bad.
That's just a default. Please see http://boost.org/libs/parameter/doc/html/reference.html#boost-parameter-max-...
Sure; you could use boost::parameter::void_ as shown here: http://boost.org/libs/parameter/doc/html/index.html#class-template-skeleton
Well, don't forget the "deduced parameter" solution; that's even better than overloads. I guess I would think first about which interface will be more expressive for your users, and second about which is more expressive for you as a library builder. If the solution with overloads results in writing lots of code, especially if there's lots of repetetive boilerplate, that's another good sign you should be doing it differently.
They serve different purposes. Do your users know which behavior they want at compile time? Also, note that one can always add a runtime choice wrapper on top of an interface that provides a compile time choice, but you can't go the other way.
Heh, heh: http://boost.org/libs/parameter/doc/html/index.html#documentation I would proably invent a hypothetical C++ declaration syntax (as though named/deduced paramters were built-in features), document that, and then document the functions in terms of it. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

They were more about the library than how to use it.
Oops... How did I manage to miss the reference documentation? I guess I need to figure out how to guarantee that I have a sufficient arity for a number Boost.Graph algorithms spread over a number of files and ensure that the arity is defined before Boost.Parameter is included.
Perfect. It's encouraging that I managed to find the same solution, albeit with my own empty struct. I hope this means I'm getting better at generic programming :) Thanks for the feedback. I'll have to spend more time poring over the notions and details of deduced parameters. We'll see what I end up with.
That's why I asked :) I was wondering if there had been any recent developments along those lines. Maybe I'll adopt some kind of python- esque model for documentation. Those guys do a pretty good job getting the point across. Andrew Sutton asutton@cs.kent.edu

on Wed Jul 11 2007, Andrew Sutton <asutton-AT-cs.kent.edu> wrote:
Yeah, well, their documentation also tends to lack crucial detail. I've seen lots of Python docs that talk about "File-like" objects without defining what that is precisely. They don't seem to have gotten Concepts yet. So, Python might make a good starting point... just make sure you don't end there, too ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

2007/7/11, Andrew Sutton <asutton@cs.kent.edu>:
Shouldn't the default arity be set to be big enough for all Boost libraries instead? Wouldn't several non-overriding defaults be a pain for users? Should the biggest of the defaults from any Boost library should be included first by the users? Or is it OK with successive redefinition (if made larger?) of the arity? (Hopefully someone can make sense of this..) /$

Not sure... I don't think there are that many Boost libraries that use Boost.Parameter so I don't believe that you'd have that too many conflicting defaults.
Successive redefinition between compiled files but it probably won't work within the same translation unit. You'd have to undef all the header guards, and that's probably going to result in some serious violations of the ODR (one definition rule). I'm probably going to end up overriding the default in my include chain, but I think the best solution may simply be to change the default in Boost.Parameter. Andrew Sutton asutton@cs.kent.edu
participants (5)
-
Andrew Sutton
-
Cédric Venet
-
David Abrahams
-
Henrik Sundberg
-
Martin Bonner