
Robert Ramey wrote:
Jeremy Siek wrote:
[suggestions] 1. Named parameters in the interface
One tiny observaton. The suggestion of named parameters for the interface could well be applied to many if not most if not all libraries. Could this not be considered as a separate orthogonal layer to the current interface? This would
a) make the named parameter interface available where convenient b) make it optional rather than obligatory c) set the precedent for other libraries which might benefit from a named parameter interface - without the need to re-do any of the library itself.
Perhaps there could even be a convention such as
boost/named_parameters/date_time.hpp ...
or perhaps
boost/date_time/named_parameters.hpp
Robert Ramey
I didn't follow the original discussion, just read David's and your's suggestions to solve "foo(int, int)" problem. And I'm in favor of your solution. If I understand it correctly, the choice is between solution 1 (David): foo(param1 = val1, param2 = val2); foo(param2 = val2, param1 = val1); and solution 2 (Robert or me if I've forgot your original idea): foo(param1_type(val1), param2_type(val2)); foo(param2_type(val2), param1_type(val1)); // NOTE: it can also be used like that param1_type p1(val1); // it can be defined in one place and used in many places param2_type p2(val2); foo(p1, p2); // It can be used in many places to reduce code bloat foo(p2, p1); // Can it be achieved with first solution? it assumes that there are strong typedefs (or Beman Davis's identifiers) for param1_type and param2_type I'm for the second solution. Anyway, as I remember from D&E book there was a proposal to add named params to the language, but it was rejected because of named params encourage procedure-style programming and C++ was positionad as a OO language. Of course, now it is positioned as a multiparadigm language, but priorities remain the same: OO is preferred over procedural in C++. or may be I'm missing something? In OO there is no reason to have naked integers that represents different logical entities. It is alway sensible to use strong type checking by making it a different types (strong typedef or identifier, or by hand) but named params are orthogonal to naked-wrapped problem it is just a syntactic sugar over already strongly typed entities. So, I'm second to Robert Ramey in "make it optional rather than obligatory" statement. But the best solution for me is - "just forget about named params" reason: consider the introductory example from boost::parameter lib: new_window("alert", width=10, titlebar=false); if I'll see such a line in a real code, my first idea would be - "there are variables width and titlebar somewhere around and this line assigns new values to them and calls a function new_window with corresponding parameters". Of course it is completely wrong. Conclusion - I'll never use this library for code that should be maintained in a long term. Note: this code compiles perfectly: void new_window(char const* const, int, bool); int main() { int width; bool titlebar; new_window("alert", width=10, titlebar=false); return 0; } The second introductory example: //-------------------------------------------------------------- Since an argument's meaning is given by its position, we have to choose an (often arbitrary) order for parameters with default values, making some combinations of defaults unusable: window* new_window( char const* name, int border_width = default_border_width, bool movable = true, bool initially_visible = true ); const bool movability = false; window* w = new_window("alert box", movability); In the example above we wanted to make an unmoveable window with a default border_width, but instead we got a moveable window with a border_width of zero. To get the desired effect, we'd need to write: window* w = new_window( "alert box", default_border_width, movability); It can become difficult for readers to understand the meaning of arguments at the call site: window* w = new_window("alert", 1, true, false); Is this window moveable and initially invisible, or unmoveable and initially visible? The reader needs to remember the order of arguments to be sure. The author of the call may not remember the order of the arguments either, leading to hard-to-find bugs. This library addresses the problems outlined above by associating each parameter with a keyword object. Now users can identify arguments by keyword, rather than by position: window* w = new_window("alert box", movable=false); // OK! //-------------------------------------------------------------- Sounds reasonable, but note drawback mentioned above. There is an alternative solution for all problems mentioned in this example: struct TWindowCreationParams { TWindowCreationParams() : border_width(default_border_width), movable(true), initially_visible(true) {} int border_width; bool movable; bool initially_visible; }; window* new_window( char const* name, TWindowCreationParams const& params ); usage becomes: TWindowCreationParams aParams; aParams.movable = false; window* w = new_window("alert box", aParams); // was: // window* w = new_window("alert box", movable=false); // // window* w = new_window("alert", 1, true, false); // becomes: // TWindowCreationParams aParams; aParams.border_width = 1; aParams.initially_visible = false; window* w = new_window("alert box", aParams); // with parameter lib it would be: // window* w = new_window("alert box", border_width = 1, initially_visible=false); The solution with auxiliary structure for parameter bundling is just slightly more verbose, but 1) it is exact (it is hard to interpret in a wrong way) 2) it doesn't pollute namespace with parameter names 3) instance of params structure can be reused many times reducing code duplication/bloating. Sorry for so long opus, but I really wonder why David Abrahams and Daniel Wallin put so great effort in the parameter lib. I can not see it's advantages. Oleg Abrosimov.