
"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
I think it should not be accepted. My main motivation is that I think it promotes an unsound growth in function interfaces.
Like having support for derivation promotes an unsound reliance on implementation inheritance and support for operators promotes abuse of operator overloading? Features don't promote practices.
I also miss a comparison of other techniques (eg. bgl_named_params, named_constructor_pattern)
I don't know about the latter. Never heard of it. But I'm guessing you're talking about something like: f(slew_is(.799), score_is(55)) If so, either it allows arbitrary parameter ordering and aside from the use of () instead of = its advantages are equivalent to those of our library, or it does not, and our library offers the advantage of freeing the user/reader/maintainer from having to remember parameter order.
to do the same and an good explanation why this approach is superior.
This approach is superior to bgl_named_params in part because it avoids undue coupling and dependency in a library design. That coupling is discussed in depth in this excerpt from C++ Template Metaprogramming (http://www.boost-consulting.com/mplbook): f(slew(.799).name("z")); Here, the expression slew(.799) would build a instance of class named_params<slew_tag, float, nil_t> having the empty class nil_t as its only base class, and containing the value .799 as a single data member. Then, its name member function would be called with "z" to produce an instance of: named_params< name_tag, char const[2] // .name("z") , named_params< slew_tag, double const // slew(.799) , nil_t >
having a copy of the instance just described as its only base, and containing a reference to "z" as its only data member. We could go into detail about how each tagged value can be extracted from such a structure, but at this point in the book we're sure your brain is already working that out for itself, so we leave it as an exercise. Instead, we'd like to focus on the chosen syntax of the DSL, and what's required to make it work. If you think for a moment about it, you'll see that not only do we need a top-level function for each parameter name (to generate the initial named_params instance in a chain), but named_params must also contain a member function for each of the parameter names we might want to follow it with. After all, we might just as well have written: f(slew(.799).score(55)); Since the named parameter interface pays off best when there are many optional parameters, and because there will probably be some overlap in the parameter names used by various functions in a given library, we're going to end up with a lot of coupling in the design. There will be a single, central named_params definition used for all functions in the library that use named parameter interfaces. Adding a new parameter name to a function declared in one header will mean going back and modifying the definition of named_params, which in turn will cause the recompilation of every translation unit that uses our named parameter interface. While writing this book, we reconsidered the interface used for named function parameter support. With a little experimentation we discovered that it's possible to provide the ideal syntax by using keyword objects with overloaded assignment operators: f(slew = .799, name = "z"); Not only is this syntax nicer for users, but adding a new parameter name is easy for the writer of the library containing f, and it doesn't cause any coupling.
Let me elaborate.
1. Clearly, this is not nice
window* w = new_window("alert", true, true, false, 77, 65);
True, but sometimes it is appropriate. Even then, you only need two parameters whose order is not obviously dictated by function to justify the use of a named parameter interface: paint(hue = 1071, luminance = 10) vs. paint(1071, 10)
However, the amount of work needed to code parameters for this is quite large.
Really? Did you compare how much work it would be to use BOOST_NAMED_PARAMS_FUN vs. what you're suggesting below?
A simple, effective way is just to do it like this:
window* w = new_window("alert"); w->set_resizable( true ); w->set_height( 77 ); ....
How would you apply that idiom to the algorithms of the Boost Graph Library?
and you might provide chaining to make it more concise. In addition there is no forwarding problems and you might have these functions anyway.
What do you mean by "you might have these functions anyway?"
2. what happens, then, if I don't have an object, but a free-standing function?
That's the main use-case of our library!
a) wrap the function in an object b) do as in http://www.boost.org/libs/graph/doc/bgl_named_params.html c) provide overloads of functions that pack related parameters together or simply add defaults
It looks like you didn't really read through the library docs. You just use the library in the normal way.
I must admit I'm a bit sceptical
That's plain! ;-)
about functions when they start having more than 3-4 arguments; there is almost always some abstraction lurking just waiting to be done.
Maybe so, but there are plenty of other good arguments for named parameters. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com