
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message news:E3214120-3D4F-11D9-836D-000D932B7224@cs.indiana.edu...
On Nov 23, 2004, at 1:10 AM, Gennadiy Rozental wrote:
Problem implement function with 2 named parameter interface where parameter 'value' is not fixed type but should comply to compile time predicate is_movable and parameter name is string:
Submitted library solution: ------------------------------
keyword<struct name_t> name; keyword<struct value_t> value;
struct f_keywords : keywords< named_param< name_t , boost::mpl::false_ , boost::is_convertible<boost::mpl::_, std::string>
, named_param< value_t , boost::mpl::false_ , is_movable<boost::mpl::_>
{};
template<typename MovableType> void f_impl(std::string name, MovableType v ) { ... }
template<class Params> void f(Params const& p, typename f_keywords::restrict<Params>::type = f_keywords()) // I am not actually quite sure whether above is a proper way to enforce a restriction { f_impl( p[name], p[value]); }
As I understand the library, the code you have written in correct.
My suggested solution ------------------------------------
typed_keyword<std::string,struct name_t> name; keyword<struct name_t> value;
template<typename MovableType> typename boost::enable_if<is_movable<MovableType>, void>::type f_impl(std::string name, MovableType v ) { ... }
template<class Params> void f(Params const& p) { f_impl( p[name], p[value]); }
------------------------------------
Now let's hear peoples subjective opinions on above choice. My position that library should only provide support for strict type checking. Any other "more flexible" restrictions are user responsibility (if necessary).
There is one subtle (but important) objective difference between the two: with the code for the library up for review, the restrictions happen for the call to "f", so if one tries to pass a non-movable type for the value, the end result will be that "f' is removed from the overload set and the compiler will emit an error stating that no call to "f" satisfies the argument list (or another "f" will be chosen). With your library, the restriction occurs at the level of "f_impl", so passing a non-movable value to "f" will actually call that "f", but the instantiation will fail within "f_impl". In essence, the library under review provides earlier checking of the arguments than your solution, so that functions that may support named parameters can be eliminated from the overload set if they don't meet the requirements.
1. It really trivial to implement the restriction on public level: template<class Params> typename boost::enable_if<is_movable<typename type_of<name,Params> >, void>::type f(Params const& p) { f_impl( p[name], p[value]); } where type_of is very simple metafunction the deduce parameter value type given parameter list and keyword. 2. I yet to see the reason why would anyone would prefer several overloads of top level interface. See below for more on this
Granted, your typed_keyword permits earlier detection of certain typing errors. For instance, if I try to write "name = 5", your library will abort the compilation at that expression but the library under review will instead remove "f" from the overload set if it is called. However, there is a potential price to be paid for this earlier checking: the name "name" has now been reserved for string parameters and cannot be reused without introducing a new "name" keyword in some other scope with a different type.
1. That is not true. Nothing prevent me from introduction of keyword name in different namespace/compilation unit. Actually in most cases I use keywords with namespace qualifiers: sock::name, cla::name, factory::name e.t.c. 2. If you implement several related function you may reuse the same typed keyword in most cases it wouldn't be an issue since all functions expect the same value type. 3. IMO It's bad idea to introduce global keywords used by various independent functions for different purposes and different data types. For example: new window( size = make_pair(10,20) ); new listbox( size = 10 ); new Jeans( size = "36x30" ); new Bowl( size = 5.675 ); I don't see above as a good practice and library shouldn't encourage it. Instead one should either use difference namespaces (see 1) or different keywords: dimensions, size, cloth_size, volume.
My (subjective) expectation is that a library may start by using typed keywords, but as the library evolves and more functions gain named parameters I'd expected those typed keywords to become non-typed keywords. There is no place in the BGL, for instance, where I would consider using a typed keyword.
That Ok. Unfortunately I am not that familiar with library but I do not believe BGL is the best example. BGL is template based library solution. In an end user's code my expectation is that in most cases one would use typed keywords.
Another subjective difference between the two is in the call to "f". The library under review supports the syntax:
f(name = "wibble", value = int);
whereas, as I understand it, your library supports the syntax:
f((name = "wibble", value = int));
I'm not going to weigh in on this issue.
Submitted library allow both syntaxes. I would never use first though. In my experience named parameters interface is most valuable facing numerous optional function arguments. Why would I want to provide 10 overloads for the same functions with different number of arguments, where 1 suffices?
Doug
Gennadiy