Named params lib review

Hi, Recently I became quite fond of interfaces with named parameters. I developed variety of different solutions with different trade-off and set of features. At first here is couple notes from my experience: 1. In most cases multiargument interface are not in high performance critical areas. 2. In many cases it's constructors. Now lets delve in more detailed discussion on: Design =============== I. Active vs. passive I found that there are two major branched in designs for named parameters: "active" parameters collection and "passive" one. Submitted library is a variation of "passive" solution: one need to call "get" method to retrieve any parameter from collection: template<typename Params> void foo( Params const& p ) { std::string name = p[name]; std::string description = p[descr]; ... } An "active" solutions automatically place parameters in appropriate slots by single 'apply' call: class A { public: template<typename Params> A( Params const& p ) { p.apply( *this ); } }; Even though "active" solutions in some cases provide an interface look more natural. I found that "passive" solution in most cases more flexible and easier to implement. While in both cases one may employ runtime polymorphism, with "passive interfaces it's more natural. Note that parameter may not necessary is just a simple value, it maybe some kind of optional feature and 'apply' method maybe not so trivial and even invoke some functions. All in all both design seems to have heir advantages and I believe we need to provide support for both flavors. II Interfaces a) Call interface and parameters combining IMO with some very rare exclusions (1/2 optional parameter) the named parameter framework shouldn't require/expect multiple overloading of target function with different number of parameters. As well as any "impl" functions. The only acceptable interface is the one with single Params template parameters (in some cases one may provide positional interface as well, though it's rather exclusion case). This is applicable both to active and passive solutions: class A { A() : ... {} template<typename Params> A( Params const& p ) : m_name( p[name] ), m_gulp( p[gulp] ) {} }; This immediately bring a need for automatic arguments combining. There are several ways to do so, depending on requirements (BWT I liked interface presented in some other post with using ',' as combine operator). b) Optional parameter support In case of active solutions there should be an interface to check presence of specific argument. Submitted solution will cause compile time error on access to non-supplied parameter. This may not be always most convenient and may not be the case at all with different implementation (runtime based) c) Default value support I specifically dislike an interfaces provided to support default values. They are unreasonably cryptic (who would remember difference between | and ||; and why | ) but also misleading since default value is actually with access brackets: what is p["abc"]? There are several alternatives. My personal preference is : int name_ = p.is_present<name> ? p[name] : "abc"; // you will need some MP trick to make it compilable or int name_ = p.is_present( name ) ? p[value] : "abc"; // this assumes runtime based implementation Active solutions doesn't have such issue. Whatever is there gets set by apply call. d) Type safety and restrictions I do not understand why wouldn't we keep data type somewhere around keyword type and require one to supply specific type during invocation.This library instead invented special mechanism of imposing restrictions. I do not believe we need that (Also my guess is that 8 out of 10 developers unfamiliar with library will be left spellbound facing this code) e) Mix of named and positional parameters I don't believe it's actually a good idea to support such mix. IMO it just adding unnecessary confusion and possible source of users errors.. Let's say I expect 2 parameters: 1. string name 2. int value. call foo( value = 5, "my_name" ) will fail, while foo( "my_name", value = 5 ) and foo( value = 5 ) won't. Too much chances to make mistake IMO. III. Implementation IMO whatever design you prefer implementation shouldn't as complex and cumbersome. Named parameters support is pretty simple task. This submission presents 1000 lines of tight MP code (and this is without numerous includes). In majority of the cases much more simple and straightforward solution is possible (with some acceptable IMO tradeoff). Following 80 lines (I think it's possible to make it even smaller would I use mpl) should basically present solution with similar tradeoff as submitted library (without default value support, but IMO it would take another 40-60 lines, just save it into keyword struct): // Library Code template<typename NP1,typename NP2> struct named_parameter_combine; template<typename T, int unique_id> struct keyword; template<typename Derived> struct named_parameter_base { template<typename NP> named_parameter_combine<NP,Derived> operator,( NP const& np ) { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived*>(this) ); } }; template<typename T, int unique_id> struct named_parameter : named_parameter_base<named_parameter<T, unique_id> > { static const int id = unique_id; named_parameter( T const& v ) : m_value( v ) {} T const& operator[]( keyword<T,unique_id> const& ) const { return m_value; } T const& m_value; }; template<bool> struct selector; template<typename NP1,typename NP2> struct named_parameter_combine : named_parameter_base<named_parameter_combine<NP1,NP2> > { named_parameter_combine( NP1 const& np1, NP2 const& np2 ) : m_np1( np1 ), m_np2( np2 ) {} template<typename KW> typename KW::data_type const& operator[]( KW const& kw ) const { return selector<KW::id==NP1::id>::_( m_np1, m_np2, kw ); } NP1 const& m_np1; NP2 const& m_np2; }; template<> struct selector<true> { template<typename NP1,typename NP2,typename KW> static typename KW::data_type const& _( NP1 const& np1, NP2 const& np2, KW const& kw ) { return np1[kw]; } }; template<> struct selector<false> { template<typename NP1,typename NP2,typename KW> static typename KW::data_type const& _( NP1 const& np1, NP2 const& np2, KW const& kw ) { return np2[kw]; } }; template<typename T, int unique_id> struct keyword { typedef T data_type; static const int id = unique_id; named_parameter<T,unique_id> operator=( T const& t ) const { return named_parameter<T,unique_id>( t ); } }; //////////////////////////////////////////////////////////////// // Example: namespace test { typedef char const* c_str; keyword<c_str,1> name; keyword <float,2> value; keyword<int,3> index; double value_default() { return 666.222; } int foo( c_str name, float v, int i ) { } template<class Params> int foo(Params const& params) { foo( params[name], params[value], params[index] ); } } int main() { using test::foo; using test::name; using test::value; using test::index; foo(( index = 20, name = "foo", value = 2.5 )); return 0; } Strict type checking on top of it. This code works under gcc 3.4.2. Should work everywhere. As you may guess by now my vote is NO to accept this library. I personally wouldn't be using it in current form and IMO as it stands now it's just another collection of neat MP tricks. I do not have to much comments on docs and tests, other then they seems incomplete. Regards, Gennadiy P.S. Why is the RC branch of mpl is different from HEAD? Doesn't we supposed to fix HEAD and only then propagate to branch?

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
An "active" solutions automatically place parameters in appropriate slots by single 'apply' call:
class A { public: template<typename Params> A( Params const& p ) { p.apply( *this ); } };
Even though "active" solutions in some cases provide an interface look more natural. I found that "passive" solution in most cases more flexible and easier to implement. While in both cases one may employ runtime polymorphism, with "passive interfaces it's more natural. Note that parameter may not necessary is just a simple value, it maybe some kind of optional feature and 'apply' method maybe not so trivial and even invoke some functions. All in all both design seems to have heir advantages and I believe we need to provide support for both flavors.
Hmm. AFAICT from your example an "active" solution requires a custom-built Params class that knows how to "apply" itself (in this case to class A). Because of that, I can't imagine what it could mean to "provide support" for an active approach. It doesn't seem like something a library can help with. Also, it seems as though the elements of the parameter infrastructure (e.g. a keyword class) will become special-purpose for the particular "apply" it needs to be able to perform, rather than reusable for several functions as in our approach. Am I missing something?
II Interfaces
a) Call interface and parameters combining
IMO with some very rare exclusions (1/2 optional parameter) the named parameter framework shouldn't require/expect multiple overloading of target function with different number of parameters. As well as any "impl" functions. The only acceptable interface is the one with single Params template parameters (in some cases one may provide positional interface as well, though it's rather exclusion case). This is applicable both to active and passive solutions:
class A { A() : ... {}
template<typename Params> A( Params const& p ) : m_name( p[name] ), m_gulp( p[gulp] ) {} };
Of course our library allows that usage. You can look on the "multiple overloading" case as though it was generated with varargs templates, which I hope we're getting in an upcoming version of C++. Hmm, we'd better make sure that feature can handle this case. ;-)
This immediately bring a need for automatic arguments combining. There are several ways to do so, depending on requirements (BWT I liked interface presented in some other post with using ',' as combine operator).
That's what our library does.
b) Optional parameter support
In case of active solutions there should be an interface to check presence of specific argument. Submitted solution will cause compile time error on access to non-supplied parameter. This may not be always most convenient and may not be the case at all with different implementation (runtime based)
It's easy enough to check, actually. struct nil_t {} nil; template <class T> bool is_nil(T&) { return false; } bool is_nil(nil_t) { return true; } now is_nil(p[name | nil]) will tell you if "name" was supplied. I guess we could build this into the library (with the corresponding compile-time check, of course).
c) Default value support
I specifically dislike an interfaces provided to support default values. They are unreasonably cryptic (who would remember difference between | and ||; and why | )
That's pretty funny; it's meant to be memnonic. We use | because it means "or," as in either get the name OR if it's not supplied, use this value We use || to indicate lazy evaluation because in C++, the 2nd argument to || isn't evaluated unless the first one is supplied. either get the name OR if it's not supplied, evaluate this function and use the result.
but also misleading since default value is actually with access brackets:
I can't parse that. In what sense is the default value "with access brackets?" Do you mean it's "accessed with brackets?" Not only the default, but also the passed value is accessed with brackets. Why is it misleading?
what is p["abc"]?
Meaningless. Compiler error. Why should it have a meaning?
There are several alternatives. My personal preference is :
int name_ = p.is_present<name> ? p[name] : "abc"; // you will need some MP trick to make it compilable or int name_ = p.is_present( name ) ? p[value] : "abc"; // this assumes ^^^^^ What's the significance of that?-------^^^^^ runtime based implementation
Active solutions doesn't have such issue. Whatever is there gets set by apply call.
Sure, but I don't see how a library can help you with it yet.
d) Type safety and restrictions
I do not understand why wouldn't we keep data type somewhere around keyword type and require one to supply specific type during invocation.
Because we looked at the use cases; the major example we could find was the Boost.Graph library, which is a library of function templates. We thought it would be bad if the library didn't work for function templates.
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
I do not believe we need that
Disagree.
(Also my guess is that 8 out of 10 developers unfamiliar with library will be left spellbound facing this code)
Possibly so.
e) Mix of named and positional parameters
I don't believe it's actually a good idea to support such mix. IMO it just adding unnecessary confusion and possible source of users errors.. Let's say I expect 2 parameters: 1. string name 2. int value. call foo( value = 5, "my_name" ) will fail, while foo( "my_name", value = 5 ) and foo( value = 5 ) won't. Too much chances to make mistake IMO.
Python and I'm sure quite a few others do it that way; experience has shown that it causes no confusion.
III. Implementation
IMO whatever design you prefer implementation shouldn't as complex and cumbersome. Named parameters support is pretty simple task. This submission presents 1000 lines of tight MP code (and this is without numerous includes). In majority of the cases much more simple and straightforward solution is possible (with some acceptable IMO tradeoff). Following 80 lines (I think it's possible to make it even smaller would I use mpl) should basically present solution with similar tradeoff as submitted library (without default value support, but IMO it would take another 40-60 lines, just save it into keyword struct):
and without the ability to control overload resolution, or to wrap function templates, and with the problem of keyword coupling (because of the integer indices). It's no fair claiming the solution should be simpler until you actually implement it. Toy examples don't count.
Strict type checking on top of it.
You say that like it's a _good_ thing.
This code works under gcc 3.4.2. Should work everywhere.
Hah! I'll believe that when you've ported it ;-)
As you may guess by now my vote is NO to accept this library. I personally wouldn't be using it in current form and IMO as it stands now it's just another collection of neat MP tricks.
It's really _just_ another collection of neat MP tricks? You mean it's not even useful? Or what, exactly? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uk6smkkiq.fsf@boost-consulting.com...
"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
An "active" solutions automatically place parameters in appropriate slots by single 'apply' call:
class A { public: template<typename Params> A( Params const& p ) { p.apply( *this ); } };
Even though "active" solutions in some cases provide an interface look more natural. I found that "passive" solution in most cases more flexible and easier to implement. While in both cases one may employ runtime polymorphism, with "passive interfaces it's more natural.
Just rereading this I realized that I actually meant it vicevisa. Active solutions are more flexible and easier to impleemnt.
Note that parameter may not necessary is just a simple value, it maybe some kind of optional feature and 'apply' method maybe not so trivial and even invoke some functions. All in all both design seems to have heir advantages and I believe we need to provide support for both flavors.
Hmm. AFAICT from your example an "active" solution requires a custom-built Params class that knows how to "apply" itself (in this case to class A). Because of that, I can't imagine what it could mean to "provide support" for an active approach. It doesn't seem like something a library can help with. Also, it seems as though the elements of the parameter infrastructure (e.g. a keyword class) will become special-purpose for the particular "apply" it needs to be able to perform, rather than reusable for several functions as in our approach. Am I missing something?
There is enough (like parameter combining anf interfaces and keywords) that could be reused in a library.
II Interfaces
a) Call interface and parameters combining
IMO with some very rare exclusions (1/2 optional parameter) the named parameter framework shouldn't require/expect multiple overloading of target function with different number of parameters. As well as any "impl" functions. The only acceptable interface is the one with single Params template parameters (in some cases one may provide positional interface as well, though it's rather exclusion case). This is applicable both to active and passive solutions:
class A { A() : ... {}
template<typename Params> A( Params const& p ) : m_name( p[name] ), m_gulp( p[gulp] ) {} };
Of course our library allows that usage. You can look on the "multiple overloading" case as though it was generated with varargs templates, which I hope we're getting in an upcoming version of C++. Hmm, we'd better make sure that feature can handle this case. ;-)
This immediately bring a need for automatic arguments combining. There are several ways to do so, depending on requirements (BWT I liked interface presented in some other post with using ',' as combine operator).
That's what our library does.
Hmm. Well, I did not find it nor in docs. Why IMO it's most important part of functionality. I see it now in test. Why did you name function f_list? Why not just f as rest of them?
b) Optional parameter support
In case of active solutions there should be an interface to check presence of specific argument. Submitted solution will cause compile time error on access to non-supplied parameter. This may not be always most convenient and may not be the case at all with different implementation (runtime based)
It's easy enough to check, actually.
struct nil_t {} nil; template <class T> bool is_nil(T&) { return false; } bool is_nil(nil_t) { return true; }
now
is_nil(p[name | nil])
will tell you if "name" was supplied. I guess we could build this into the library (with the corresponding compile-time check, of course).
It could be usefull.
c) Default value support
I specifically dislike an interfaces provided to support default values. They are unreasonably cryptic (who would remember difference between | and ||; and why | )
That's pretty funny; it's meant to be memnonic.
We use | because it means "or," as in
either get the name OR if it's not supplied, use this value
We use || to indicate lazy evaluation because in C++, the 2nd argument to || isn't evaluated unless the first one is supplied.
either get the name OR if it's not supplied, evaluate this function and use the result.
but also misleading since default value is actually with access brackets:
I can't parse that. In what sense is the default value "with access brackets?" Do you mean it's "accessed with brackets?"
I meant "within brackets". My problem is that it's p[name | "abc"] while I would prefer something like p[name] | "abc". Or even better something like a nexplicit interface below.
There are several alternatives. My personal preference is :
int name_ = p.is_present<name> ? p[name] : "abc"; // you will need some MP trick to make it compilable or int name_ = p.is_present( name ) ? p[value] : "abc"; // this assumes ^^^^^ What's the significance of that?-------^^^^^
Could you rephrase the question? It's just an interface I would prefer.
runtime based implementation
Active solutions doesn't have such issue. Whatever is there gets set by apply call.
Sure, but I don't see how a library can help you with it yet.
It could. I did that.
d) Type safety and restrictions
I do not understand why wouldn't we keep data type somewhere around keyword type and require one to supply specific type during invocation.
Because we looked at the use cases; the major example we could find was the Boost.Graph library, which is a library of function templates. We thought it would be bad if the library didn't work for function templates.
Sorry I am not familier with that example. Could you please give more details on what exactly is wrong wit hstrict type checking?
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
Yeah. But in C++ de-facto standard approach for enforcing parameters types is to specify one.
e) Mix of named and positional parameters
I don't believe it's actually a good idea to support such mix. IMO it just adding unnecessary confusion and possible source of users errors.. Let's say I expect 2 parameters: 1. string name 2. int value. call foo( value = 5, "my_name" ) will fail, while foo( "my_name", value = 5 ) and foo( value = 5 ) won't. Too much chances to make mistake IMO.
Python and I'm sure quite a few others do it that way; experience has shown that it causes no confusion.
III. Implementation
IMO whatever design you prefer implementation shouldn't as complex and cumbersome. Named parameters support is pretty simple task. This submission presents 1000 lines of tight MP code (and this is without numerous includes). In majority of the cases much more simple and straightforward solution is possible (with some acceptable IMO tradeoff). Following 80
(I think it's possible to make it even smaller would I use mpl) should basically present solution with similar tradeoff as submitted library (without default value support, but IMO it would take another 40-60
I do not know about python, but in c++ I prefer named interface wouldn't break by switching order of parameter specification. lines lines,
just save it into keyword struct):
and without the ability to control overload resolution,
What do you mean here? With an example.
or to wrap function templates
Or this?
and with the problem of keyword coupling (because of the integer indices).
What do you mean by coupling? That we need to supply unique integer id? I do not see it as a major drawback. And it's definetly justified by the simplicity of the solution.
It's no fair claiming the solution should be simpler until you actually implement it. Toy examples don't count.
I did. And I do not believe it's toy example (at least no more that submitted library). It does everything I need from named parameters, easy to use and does not cost a lot.
Strict type checking on top of it.
You say that like it's a _good_ thing.
Yes. I do believe strict type checking is good thing for both positional and named function parameters.
This code works under gcc 3.4.2. Should work everywhere.
Hah! I'll believe that when you've ported it ;-)
I did not use any advanced features (I don't think even PS). I did ported similar solutions on numerous compilers.
As you may guess by now my vote is NO to accept this library. I personally wouldn't be using it in current form and IMO as it stands now it's just another collection of neat MP tricks.
It's really _just_ another collection of neat MP tricks? You mean it's not even useful? Or what, exactly?
I wouldn't be using it. Why would I use canon to kill sparrow.
-- Dave Abrahams
Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uk6smkkiq.fsf@boost-consulting.com...
Hmm. AFAICT from your example an "active" solution requires a custom-built Params class that knows how to "apply" itself (in this case to class A). Because of that, I can't imagine what it could mean to "provide support" for an active approach. It doesn't seem like something a library can help with. Also, it seems as though the elements of the parameter infrastructure (e.g. a keyword class) will become special-purpose for the particular "apply" it needs to be able to perform, rather than reusable for several functions as in our approach. Am I missing something?
There is enough (like parameter combining anf interfaces and keywords) that could be reused in a library.
Sure. It's just the "active" part that the library can't support. You can always use a passive approach and then do the extraction using the library primitives inside the "apply" function. After all, why not make "apply" a free function? template <class Params> void apply(Params& p, Whatever x) { // use p's "passive" interface to operate on x }
This immediately bring a need for automatic arguments combining. There are several ways to do so, depending on requirements (BWT I liked interface presented in some other post with using ',' as combine operator).
That's what our library does.
Hmm. Well, I did not find it nor in docs. Why IMO it's most important part of functionality. I see it now in test. Why did you name function f_list? Why not just f as rest of them?
Where are you seeing f_list?
It's easy enough to check, actually.
struct nil_t {} nil; template <class T> bool is_nil(T&) { return false; } bool is_nil(nil_t) { return true; }
now
is_nil(p[name | nil])
will tell you if "name" was supplied. I guess we could build this into the library (with the corresponding compile-time check, of course).
It could be usefull.
Yes.
c) Default value support
I specifically dislike an interfaces provided to support default values. They are unreasonably cryptic (who would remember difference between | and ||; and why | )
That's pretty funny; it's meant to be memnonic.
We use | because it means "or," as in
either get the name OR if it's not supplied, use this value
We use || to indicate lazy evaluation because in C++, the 2nd argument to || isn't evaluated unless the first one is supplied.
either get the name OR if it's not supplied, evaluate this function and use the result.
but also misleading since default value is actually with access brackets:
I can't parse that. In what sense is the default value "with access brackets?" Do you mean it's "accessed with brackets?"
I meant "within brackets". My problem is that it's p[name | "abc"] while I would prefer something like p[name] | "abc".
That's not doable in general. Suppose the argument was an int? What is p[index] | 3 ??
Or even better something like a nexplicit interface below.
There are several alternatives. My personal preference is :
int name_ = p.is_present<name> ? p[name] : "abc"; // you will need some MP trick to make it compilable or int name_ = p.is_present( name ) ? p[value] : "abc"; // this assumes ^^^^^ What's the significance of that?-------^^^^^
Could you rephrase the question?
You used value instead of name in the 2nd example.
It's just an interface I would prefer.
If we provide the interface you requested, to query whether a value is supplied, then you could have your "explicit interface" too. It's a little verbose for my tastes, but to each his own I guess.
runtime based implementation
Active solutions doesn't have such issue. Whatever is there gets set by apply call.
Sure, but I don't see how a library can help you with it yet.
It could. I did that.
Please show how the library can help with the "active" part. The passive library can be used to build an active component easily enough. I just don't see how the library can help with the apply call.
Because we looked at the use cases; the major example we could find was the Boost.Graph library, which is a library of function templates. We thought it would be bad if the library didn't work for function templates.
Sorry I am not familier with that example. Could you please give more details on what exactly is wrong wit hstrict type checking?
If you have a templated function parameter that you want to be able to name, you can't require that it is one particular type. template <class T> void f(T x); // what strict type is T? Now, you *can* leave it completely unchecked, but that's often overly general and can lead to overload ambiguity/conflicts. Our mechanism allows you to restrict the types of arguments. It means that in the trivial case where the argument has to be a particular type, you write is_same<_, SomeType> instead of SomeType A small price to pay.
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
Yeah. But in C++ de-facto standard approach for enforcing parameters types is to specify one.
Unless you're writing a function template.
e) Mix of named and positional parameters
I don't believe it's actually a good idea to support such mix. IMO it just adding unnecessary confusion and possible source of users errors.. Let's say I expect 2 parameters: 1. string name 2. int value. call foo( value = 5, "my_name" ) will fail, while foo( "my_name", value = 5 ) and foo( value = 5 ) won't. Too much chances to make mistake IMO.
Python and I'm sure quite a few others do it that way; experience has shown that it causes no confusion.
I do not know about python, but in c++ I prefer named interface wouldn't break by switching order of parameter specification.
What do you mean by "break?" When parameter names are used there is no restriction on parameter order. f(arg1, arg2, arg3, key5 = arg5, key6 = arg6, key4 = arg4) ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positional position-independent.
III. Implementation
IMO whatever design you prefer implementation shouldn't as complex and cumbersome. Named parameters support is pretty simple task. This submission presents 1000 lines of tight MP code (and this is without numerous includes). In majority of the cases much more simple and straightforward solution is possible (with some acceptable IMO tradeoff). Following 80 lines (I think it's possible to make it even smaller would I use mpl) should basically present solution with similar tradeoff as submitted library (without default value support, but IMO it would take another 40-60 lines, just save it into keyword struct):
and without the ability to control overload resolution,
What do you mean here? With an example.
or to wrap function templates
Or this?
These two are related; it should be clear from what I've written above. Your code can allow at most one of these (I didn't check): either it allows unchecked types and there's no ability to control overload resolution, or it doesn't support function templates with keyword arguments. And unless you have some way to induce SFINAE, you have no way to distinguish multiple overloads of the same function name accepting different named parameter sets: int foo1( c_str name, float v, int i ) { } int foo2( int id ) { } template<class Params> int foo(Params const& params) { foo1( params[name], params[value], params[index] ); } template<class Params> int foo(Params const& params) // error, foo already defined. { foo2( params[id] ); }
and with the problem of keyword coupling (because of the integer indices).
What do you mean by coupling? That we need to supply unique integer id?
Yes. You can't develop keywords independently.
I do not see it as a major drawback. And it's definetly justified by the simplicity of the solution.
I prefer to have a little more complexity in the library to remove problems for the user.
It's no fair claiming the solution should be simpler until you actually implement it. Toy examples don't count.
I did. And I do not believe it's toy example (at least no more that submitted library). It does everything I need from named parameters, easy to use and does not cost a lot.
Fair enough.
Strict type checking on top of it.
You say that like it's a _good_ thing.
Yes. I do believe strict type checking is good thing for both positional and named function parameters.
But it kills function templates. Function templates don't just accept a single type.
This code works under gcc 3.4.2. Should work everywhere.
Hah! I'll believe that when you've ported it ;-)
I did not use any advanced features (I don't think even PS). I did ported similar solutions on numerous compilers.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
As you may guess by now my vote is NO to accept this library. I personally wouldn't be using it in current form and IMO as it stands now it's just another collection of neat MP tricks.
It's really _just_ another collection of neat MP tricks? You mean it's not even useful? Or what, exactly?
I wouldn't be using it. Why would I use canon to kill sparrow.
Why would anyone kill a sparrow?!! ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

using the library primitives inside the "apply" function. After all, why not make "apply" a free function?
template <class Params> void apply(Params& p, Whatever x) { // use p's "passive" interface to operate on x }
This looks like good idea, but as it is you couldn't put it into library, since you don't know which interface to use to operate on x. What you could do is to make above function to apply all params to x template <class Params> void apply(Params& p, Whatever x) { for_each<Param>( do_apply_to(x) ); } and user will be required to write do_apply functions: void do_apply( name_param, A& a ) { a.m_name = name_param.value; } void do_apply( suffix_param, A& a ) { a.m_name.append( name_param.value ); } void do_apply( prefix_param, A& a ) { a.m_name.prepend( name_param.value ); }
Hmm. Well, I did not find it nor in docs. Why IMO it's most important part of functionality. I see it now in test. Why did you name function f_list? Why not just f as rest of them?
Where are you seeing f_list?
In your test program.
I meant "within brackets". My problem is that it's p[name | "abc"] while I would prefer something like p[name] | "abc".
That's not doable in general. Suppose the argument was an int? What is
p[index] | 3
??
Yeah,. I understand.it's not possible. But within brackets is not very good either IMO
It's just an interface I would prefer.
If we provide the interface you requested, to query whether a value is supplied, then you could have your "explicit interface" too. It's a little verbose for my tastes, but to each his own I guess.
It could. I did that.
Please show how the library can help with the "active" part. The passive library can be used to build an active component easily enough. I just don't see how the library can help with the apply call.
Yes. User will be required to implement all apply calls for all parameters. Note though: 1. "Passive" solution does require the same: one need to 'apply' (assign) named parameter value to the target at the point of usage (not in the library) 2. In case of "active" solution you actually do it once and then could reuse it for many different functions class Entry { }; class Logger { public: template<Params> log( msg, Params p ) { Entry e( msg ); p.apply_to( e ); e.flush(); } template<Params> buffer( msg, Params p ) { m_entries.push_back( Entry( msg ) ); p.apply_to( m_entries.back() ); } template<Params> buffer( multichunk_msg, Params p ) { m_entries.push_back( Entry( multichunk_msg ) ); p.apply_to( m_entries.back() ); } vector<Entry> m_entries; };
Because we looked at the use cases; the major example we could find was the Boost.Graph library, which is a library of function templates. We thought it would be bad if the library didn't work for function templates.
Sorry I am not familiar with that example. Could you please give more details on what exactly is wrong wit strict type checking?
If you have a templated function parameter that you want to be able to name, you can't require that it is one particular type.
template <class T> void f(T x); // what strict type is T?
Sorry. I still not sure I understand. Let me put it as following example: template<typename T> void log( std::string prefix, std::string name, std::string separ, T const& v ) { std::cout << prefix << name << separ << v; } template<typename Params> void log( Params const& p ) { log( p[prefix | "" ], p[name], p[separator | " = " ], p[value] ); } Yeah. In this case keyword "value" couldn't be typed. Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use). I also eliminated "keyword coupling". Now it should be as good in this regard as submitted library.
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
Yeah. But in C++ de-facto standard approach for enforcing parameters types is to specify one.
Unless you're writing a function template.
If you have named template parameter it should be non-typed. In other case it should be typed.
I do not know about python, but in c++ I prefer named interface wouldn't break by switching order of parameter specification.
What do you mean by "break?" When parameter names are used there is no restriction on parameter order.
f(arg1, arg2, arg3, key5 = arg5, key6 = arg6, key4 = arg4) ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positional position-independent.
Let consider an example of two optional parameters name, value. Then foo( "abc", value = 5 ) works foo( value = 5 ) works foo( value = 5, "abc" ) doesn't work.
These two are related; it should be clear from what I've written above. Your code can allow at most one of these (I didn't check): either it allows unchecked types and there's no ability to control overload resolution, or it doesn't support function templates with keyword arguments. And unless you have some way to induce SFINAE, you have no way to distinguish multiple overloads of the same function name accepting different named parameter sets:
int foo1( c_str name, float v, int i ) { }
int foo2( int id )
But you sad "multiple overloads of the same function" Above should look like int foo1( int id )
{ }
template<class Params> int foo(Params const& params) { foo1( params[name], params[value], params[index] ); }
template<class Params> int foo(Params const& params) // error, foo already defined. { foo2( params[id] ); }
We don't need two. I would write: template<class Params> int foo(Params const& params) { if( name and value present ) foo1( params[name], params[value], params[index] ); else foo1( params[index] ); }
and with the problem of keyword coupling (because of the integer indices).
What do you mean by coupling? That we need to supply unique integer id?
Yes. You can't develop keywords independently.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
Do we still care? Enough to affect the design/implementation?
I wouldn't be using it. Why would I use canon to kill sparrow.
Why would anyone kill a sparrow?!! ;-)
It's just Russian saying I was trying to translate. Don't know English equivalent.
Dave Abrahams
Gennadiy begin 666 b.cpp M(VEN8VQU9&4@/&)O;W-T+VUP;"]J;VEN=%]V:65W+FAP<#X*(VEN8VQU9&4@ M/&)O;W-T+VUP;"]D97)E9BYH<' ^"B-I;F-L=61E(#QB;V]S="]M<&PO9FEN M9%]I9BYH<' ^"B-I;F-L=61E(#QB;V]S="]M<&PO;&ES="YH<' ^"B-I;F-L M=61E(#QB;V]S="]T>7!E7W1R86ET<R]I<U]S86UE+FAP<#X*"FYA;65S<&%C M92!M<&P@/2!B;V]S=#HZ;7!L.PH*+R\@3&EB<F%R>2!#;V1E"G1E;7!L871E M/'1Y<&5N86UE($Y0,2QT>7!E;F%M92!.4#(^(" @(" @<W1R=6-T(&YA;65D M7W!A<F%M971E<E]C;VUB:6YE.PIT96UP;&%T93QT>7!E;F%M92!4+"!T>7!E M;F%M92!U;FEQ=65?:60^('-T<G5C="!N86UE9%]P87)A;65T97(["G1E;7!L M871E/'1Y<&5N86UE('5N:7%U95]I9#X@(" @(" @(" @(" @<W1R=6-T(&ME M>7=O<F0["G1E;7!L871E/'1Y<&5N86UE(%0L('1Y<&5N86UE('5N:7%U95]I M9#X@<W1R=6-T('1Y<&5D7VME>7=O<F0["@IT96UP;&%T93QT>7!E;F%M92!) M9#X*<W1R=6-T(&AA<U]I9 I["B @("!T96UP;&%T93QT>7!E;F%M92!.4#X* M(" @('-T<G5C="!A<'!L>0H@(" @>PH@(" @(" @('1Y<&5D968@='EP96YA M;64@8F]O<W0Z.FES7W-A;64\='EP96YA;64@3E Z.FED+$ED/CHZ='EP92!T M>7!E.PH@(" @?3L*?3L*"G1E;7!L871E/'1Y<&5N86UE(%!A<F%M5'EP97,L M='EP96YA;64@260^"G-T<G5C="!T>7!E7V]F7VYP( I["B @('1Y<&5D968@ M='EP96YA;64@;7!L.CIF:6YD7VEF/%!A<F%M5'EP97,L:&%S7VED/$ED/B ^ M.CIT>7!E(&ET97(["@H@("!T>7!E9&5F('1Y<&5N86UE(&UP;#HZ9&5R968\ M:71E<CXZ.G1Y<&4Z.F1A=&%?='EP92!T>7!E.PH*?3L*"G1E;7!L871E/'1Y M<&5N86UE($1E<FEV960^"G-T<G5C="!N86UE9%]P87)A;65T97)?8F%S90I[ M"B @("!T96UP;&%T93QT>7!E;F%M92!.4#X*(" @(&YA;65D7W!A<F%M971E M<E]C;VUB:6YE/$Y0+$1E<FEV960^"B @("!O<&5R871O<BPH($Y0(&-O;G-T M)B!N<" I"B @("!["B @(" @(" @<F5T=7)N(&YA;65D7W!A<F%M971E<E]C M;VUB:6YE/$Y0+$1E<FEV960^*"!N<"P@*G-T871I8U]C87-T/$1E<FEV960J M/BAT:&ES*2 I.PH@(" @?0I].PH*=&5M<&QA=&4\='EP96YA;64@5"P@='EP M96YA;64@=6YI<75E7VED/@IS=')U8W0@;F%M961?<&%R86UE=&5R"CH@;F%M M961?<&%R86UE=&5R7V)A<V4\;F%M961?<&%R86UE=&5R/%0L('5N:7%U95]I M9#X@/@I["B @("!T>7!E9&5F(%0@(" @(" @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @(&1A=&%?='EP93L*(" @('1Y<&5D968@;7!L.CIL M:7-T,3QN86UE9%]P87)A;65T97(\5"QU;FEQ=65?:60^(#X@<&%R86U?='EP M93L*(" @('1Y<&5D968@=6YI<75E7VED(" @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @:60["@H@(" @;F%M961?<&%R86UE=&5R*"!4(&-O;G-T M)B!V("D@.B!M7W9A;'5E*"!V("D@>WT*"B @("!4(&-O;G-T)B!O<&5R871O M<EM=*"!K97EW;W)D/'5N:7%U95]I9#X@8V]N<W0F("D@8V]N<W0@>R!R971U M<FX@;5]V86QU93L@?0H*(" @(%0@8V]N<W0F(&U?=F%L=64["GT["@IT96UP M;&%T93QT>7!E;F%M92!R97-?='EP93X*<W1R=6-T(&%C8V5S<U]F:7)S= I[ M"B @("!T96UP;&%T93QT>7!E;F%M92!.4#$L='EP96YA;64@3E R+'1Y<&5N M86UE($M7/@H@(" @<W1A=&EC(')E<U]T>7!E(&-O;G-T)B!?*"!.4#$@8V]N M<W0F(&YP,2P@3E R(&-O;G-T)B!N<#(L($M7(&-O;G-T)B!K=R I('L@<F5T M=7)N(&YP,5MK=UT[('T*?3L*"G1E;7!L871E/'1Y<&5N86UE(')E<U]T>7!E M/@IS=')U8W0@86-C97-S7W)E<W0*>PH@(" @=&5M<&QA=&4\='EP96YA;64@ M3E Q+'1Y<&5N86UE($Y0,BQT>7!E;F%M92!+5SX*(" @('-T871I8R!R97-? M='EP92!C;VYS="8@7R@@3E Q(&-O;G-T)B!N<#$L($Y0,B!C;VYS="8@;G R M+"!+5R!C;VYS="8@:W<@*2![(')E='5R;B!N<#);:W==.R!]"GT["@IT96UP M;&%T93QT>7!E;F%M92!.4#$L='EP96YA;64@3E R/@IS=')U8W0@;F%M961? M<&%R86UE=&5R7V-O;6)I;F4*.B!N86UE9%]P87)A;65T97)?8F%S93QN86UE M9%]P87)A;65T97)?8V]M8FEN93Q.4#$L3E R/B ^"GL*(" @('1Y<&5D968@ M;7!L.CIJ;VEN=%]V:65W/'1Y<&5N86UE($Y0,3HZ<&%R86U?='EP92QT>7!E M;F%M92!.4#(Z.G!A<F%M7W1Y<&4^('!A<F%M7W1Y<&4["@H@(" @;F%M961? M<&%R86UE=&5R7V-O;6)I;F4H($Y0,2!C;VYS="8@;G Q+"!.4#(@8V]N<W0F M(&YP,B I"B @(" Z(&U?;G Q*"!N<#$@*2P@;5]N<#(H(&YP,B I"B @("![ M?0H*(" @('1E;7!L871E/'1Y<&5N86UE($M7/@H@(" @='EP96YA;64@='EP M95]O9E]N<#QP87)A;5]T>7!E+'1Y<&5N86UE($M7.CII9#XZ.G1Y<&4@8V]N M<W0F( H@(" @;W!E<F%T;W);72@@2U<@8V]N<W0F(&MW("D@8V]N<W0*(" @ M('L@"B @(" @("!T>7!E9&5F('1Y<&5N86UE('1Y<&5?;V9?;G \<&%R86U? M='EP92QT>7!E;F%M92!+5SHZ:60^.CIT>7!E(')E<U]T>7!E.PH@(" @(" @ M='EP961E9B!T>7!E;F%M92!M<&PZ.FEF7SQB;V]S=#HZ:7-?<V%M93QT>7!E M;F%M92!+5SHZ:60L='EP96YA;64@3E Q.CII9#XL"B @(" @(" @("!A8V-E M<W-?9FER<W0\<F5S7W1Y<&4^+&%C8V5S<U]R97-T/')E<U]T>7!E/B ^.CIT M>7!E(&%C8V5S<V]R.PH@"B @(" @("!R971U<FX@86-C97-S;W(Z.E\H(&U? M;G Q+"!M7VYP,BP@:W<@*3L*(" @('T*"B @("!.4#$@8V]N<W0F(&U?;G Q M.PH@(" @3E R(&-O;G-T)B!M7VYP,CL*?3L*"G1E;7!L871E/'1Y<&5N86UE M('5N:7%U95]I9#X*<W1R=6-T(&ME>7=O<F0*>PH@(" @='EP961E9B!U;FEQ M=65?:60@:60["@H@(" @=&5M<&QA=&4\='EP96YA;64@5#X*(" @(&YA;65D M7W!A<F%M971E<CQ4+'5N:7%U95]I9#X*(" @(&]P97)A=&]R/2@@5"!C;VYS M="8@=" I(&-O;G-T"B @("!["B @(" @(" @<F5T=7)N(&YA;65D7W!A<F%M M971E<CQ4+'5N:7%U95]I9#XH('0@*3L*(" @('T*?3L*"G1E;7!L871E/'1Y M<&5N86UE(%0L('1Y<&5N86UE('5N:7%U95]I9#X*<W1R=6-T('1Y<&5D7VME M>7=O<F0@.B!K97EW;W)D/'5N:7%U95]I9#X*>PH@(" @;F%M961?<&%R86UE M=&5R/%0L=6YI<75E7VED/@H@(" @;W!E<F%T;W(]*"!4(&-O;G-T)B!T("D@ M8V]N<W0*(" @('L*(" @(" @("!R971U<FX@;F%M961?<&%R86UE=&5R/%0L M=6YI<75E7VED/B@@=" I.PH@(" @?0I].PH*+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+PHO+R!%>&%M<&QE.@H*(VEN8VQU9&4@/&EO<W1R96%M/@H*;F%M97-P86-E M('1E<W0*>PH@('1Y<&5D7VME>7=O<F0\8VAA<B!C;VYS="HL<W1R=6-T(&YA M;65?=#X@;F%M93L*("!T>7!E9%]K97EW;W)D/&EN="QS=')U8W0@:6YD97A? M=#X@(" @(" @(&EN9&5X.PH@(&ME>7=O<F0\<W1R=6-T('9A;'5E7W0^(" @ M(" @(" @(" @(" @(" @=F%L=64["@H@('1E;7!L871E/'1Y<&5N86UE(%9A M;'5E5'EP93X*("!I;G0@9F]O*"!C:&%R(&-O;G-T*B!N+"!686QU951Y<&4@ M=BP@:6YT(&D@*0H@('L*(" @(" @<W1D.CIC;W5T(#P\(&X@/#P@)ULG(#P\ M(&D@/#P@(ET](B \/"!V(#P\('-T9#HZ96YD;#L*("!]"@H@('1E;7!L871E M/&-L87-S(%!A<F%M<SX*("!I;G0@9F]O*%!A<F%M<R!C;VYS="8@<&%R86US M*0H@('L*(" @(" @9F]O*"!P87)A;7-;;F%M95TL('!A<F%M<UMV86QU95TL M('!A<F%M<UMI;F1E>%T@*3L*("!]"GT*"FEN="!M86EN*"D*>PH@("!U<VEN M9R!T97-T.CIF;V\["B @('5S:6YG('1E<W0Z.FYA;64["B @('5S:6YG('1E M<W0Z.G9A;'5E.PH@("!U<VEN9R!T97-T.CII;F1E>#L*"B @(&9O;R@H(&EN M9&5X(#T@,"P@;F%M92 ](")F;V\B+"!V86QU92 ](#(N-2 I*3L*(" @9F]O M*"@@:6YD97@@/2 Q+"!N86UE(#T@(F9O;R(L('9A;'5E(#T@)V$G("DI.PH@ M("!F;V\H*"!I;F1E>" ](#(L(&YA;64@/2 B9&]O(BP@=F%L=64@/2 B86)C 7(B I*3L*"@H@("!R971U<FX@,#L*?0H` ` end

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:cndq2e$fiq$1@sea.gmane.org... | > > I wouldn't be using it. Why would I use canon to kill sparrow. | > | > Why would anyone kill a sparrow?!! ;-) | | It's just Russian saying I was trying to translate. Don't know English | equivalent. We have the saying in Danish too. Well chosen. -Thorsten

On Tuesday, November 16, 2004, at 05:41 PM, Thorsten Ottosen wrote:
"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:cndq2e$fiq$1@sea.gmane.org...
| > > I wouldn't be using it. Why would I use canon to kill sparrow. | > | > Why would anyone kill a sparrow?!! ;-) | | It's just Russian saying I was trying to translate. Don't know English | equivalent.
We have the saying in Danish too. Well chosen.
-Thorsten
In American English: "Don't use a cannon to kill a mosquito" FWIW, Note the imperative form :-)

Gennadiy Rozental wrote: [snip]
Yeah. In this case keyword "value" couldn't be typed. Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use).
It's only 120 (instead of 800) lines because you haven't implemented the features and workarounds that our library has. It's not like we've written ~600 lines of useless code that can just be eliminated..
and with the problem of keyword coupling (because of the integer
indices).
What do you mean by coupling? That we need to supply unique integer id?
Yes. You can't develop keywords independently.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
But the type should never be part of the keyword! It has to be coupled with the function. Keywords needs to be reusable between different functions.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
Do we still care?
I don't know if you do. But there are certainly other people who do.
Enough to affect the design/implementation?
We have made NO compromises in the design of this library to help less capable compilers. What does it matter if the implementation contains workarounds? Why do you care? -- Daniel Wallin

"Daniel Wallin" <dalwan01@student.umu.se> wrote in message news:cne6k4$dpl$1@sea.gmane.org...
Gennadiy Rozental wrote: [snip]
Yeah. In this case keyword "value" couldn't be typed. Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use).
It's only 120 (instead of 800) lines because you haven't implemented the features and workarounds that our library has. It's not like we've written ~600 lines of useless code that can just be eliminated..
My code works without *any* modifications on: gcc 2.95.3 gcc 3.2.3 gcc 3.4.2 borland 5.6.4 cw 8.3 vc7.1(+/-stlport) vc6.5 (well this guy does require to change typename to BOOST_DEDUCED_TYPENAME in couple places, but that's it) Don't have other compilers to check.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
But the type should never be part of the keyword!
Well, I strongly disagree here.
It has to be coupled with the function. ?
Keywords needs to be reusable between different functions.
Why would I want this: In one place parameter abc is string in another is float? IMO it's very rarely make sence and I would use non-typed keyword in this case. In majority of the usage cases I would use typed one though.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
Do we still care?
I don't know if you do. But there are certainly other people who do.
Enough to affect the design/implementation?
We have made NO compromises in the design of this library to help less capable compilers. What does it matter if the implementation contains workarounds? Why do you care?
I don't , but I did not bring it into discussion. My point is that it shouldn't matter and shouldn't come up. If you do support it - good, if not - ... also good.
-- Daniel Wallin

Gennadiy Rozental wrote:
"Daniel Wallin" <dalwan01@student.umu.se> wrote in message news:cne6k4$dpl$1@sea.gmane.org...
Gennadiy Rozental wrote: [snip]
Yeah. In this case keyword "value" couldn't be typed. Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use).
It's only 120 (instead of 800) lines because you haven't implemented the features and workarounds that our library has. It's not like we've written ~600 lines of useless code that can just be eliminated..
My code works without *any* modifications on:
gcc 2.95.3 gcc 3.2.3 gcc 3.4.2 borland 5.6.4 cw 8.3 vc7.1(+/-stlport) vc6.5 (well this guy does require to change typename to BOOST_DEDUCED_TYPENAME in couple places, but that's it)
Again, you are lacking almost every feature we support. Furthermore, you have O(N) instantiations for every lookup, we have O(1). Actually you seem to have an mpl::find_if<> instantiation for every one of those, so make that O(N^2). Preprocessed for GCC, the library is 580 lines of code. If you don't need some of the features we have, why don't you just not use those features instead of rolling your own version of the library? Is parsing 400 lines really a big deal?
I do not see to many differences from your solution. You also need
unique id
for the keyword, which you then organize in ordered structure. So essentially getting the same result.
But the type should never be part of the keyword!
Well, I strongly disagree here.
Fine.
It has to be coupled with the function.
?
The argument type requirements of a function is best coupled with the function, not the argument identifier.
Keywords needs to be reusable between different functions.
Why would I want this: In one place parameter abc is string in another is float? IMO it's very rarely make sence and I would use non-typed keyword in this case. In majority of the usage cases I would use typed one though.
Are you saying argument names are in general picked to unambiguously reflect their type? void f(float size); void g(vec2d size); Who decides if 'size' is non-typed or not? Who decides if 'size' has a default value, or is a required parameter? (I know your code doesn't support that, but still..). -- Daniel Wallin

Yeah. In this case keyword "value" couldn't be typed. Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use).
It's only 120 (instead of 800) lines because you haven't implemented the features and workarounds that our library has. It's not like we've written ~600 lines of useless code that can just be eliminated..
My code works without *any* modifications on:
gcc 2.95.3 gcc 3.2.3 gcc 3.4.2 borland 5.6.4 cw 8.3 vc7.1(+/-stlport) vc6.5 (well this guy does require to change typename to BOOST_DEDUCED_TYPENAME in couple places, but that's it)
Again, you are lacking almost every feature we support.
Let's not make populist statements. I prefer discussion based on simple examples. "Here is what my solution can do, but you can't; Here is an interface I provide, here is what you do" e.t.c. In my opinion my solution only lacks some kind of default value support. While provide notion of typed keyword.
Furthermore, you have O(N) instantiations for every lookup, we have O(1).
I do not understand your code that well to contradict you, but I frankly very much doubt so.
Actually you seem to have an mpl::find_if<> instantiation for every one of those, so make that O(N^2).
I use mpl algorithm to speed up delepoment. I may've use my own list implementation, as you do. And I don't expect it to see signifant diffence in both complexity and performance.
It has to be coupled with the function.
?
The argument type requirements of a function is best coupled with the function, not the argument identifier.
I consider keyword as a part of function interface and not a standalone thing. keyword name could designate: object identifier, object property, IP service string and many other things. Why would I ever want to invent global shared name keyword and used it anytime I want parameter name amoung my function parameters??
Keywords needs to be reusable between different functions.
Why would I want this: In one place parameter abc is string in another is float? IMO it's very rarely make sence and I would use non-typed keyword in this case. In majority of the usage cases I would use typed one though.
Are you saying argument names are in general picked to unambiguously reflect their type?
void f(float size); void g(vec2d size);
Who decides if 'size' is non-typed or not? You are. If you believe that these two functions are related as well as
how f size parameter is related to g size? I would call one 'length' and second area. their parameters you may name them the same and share the keyword. It may happend that actual data type is different (or template parameter), then you would use typeless keyword: class A { A( std::string name, ... ) A( char const* name, ... ) A( const_string name, ... ) template<Params> A( Params const& ) ... }; new A( name = "abd" ); new A( name = std::string() ); new A( name = const_string() );
Who decides if 'size' has a default value, or is a required parameter? (I know your code doesn't support that, but still..).
I am not sure I understand what is you point here. All 'questions' have an answer - you - library user.
-- Daniel Wallin
Gennadiy.

Furthermore, you have O(N) instantiations for every lookup, we have O(1).
I do not understand your code that well to contradict you, but I frankly very much doubt so.
Ok. I think I see where O(1) comes from. I've reimplemented my solution based on similar idea. Now the total size is ~60 lines and without *any* includes (see attached). And it support 1. typed keywords to support strict type checking 2. non-typed keywords to support template functions parameters 3. optional parameters and default values ( could use with runtime if without compile-time errors) What are the other "every feature you support" but I don't? Gennadiy. begin 666 d.cpp M+R\@3&EB<F%R>2!#;V1E"G1E;7!L871E/'1Y<&5N86UE($Y0,2QT>7!E;F%M M92!.4#(^(" @(" @<W1R=6-T(&YA;65D7W!A<F%M971E<E]C;VUB:6YE.PIT M96UP;&%T93QT>7!E;F%M92!4+"!T>7!E;F%M92!U;FEQ=65?:60^('-T<G5C M="!N86UE9%]P87)A;65T97(["G1E;7!L871E/'1Y<&5N86UE('5N:7%U95]I M9#X@(" @(" @(" @(" @<W1R=6-T(&ME>7=O<F0["@IS=')U8W0@;FEL('L* M(" @('1E;7!L871E/'1Y<&5N86UE(%0^(&]P97)A=&]R(%0H*2![('1H<F]W M(")A8V-E<W-?=&]?:6YV86QI9%]P87)A;65T97(B.R!R971U<FX@*BA4*BDP M.R!]"GT["@IT96UP;&%T93QT>7!E;F%M92!$97)I=F5D/@IS=')U8W0@;F%M M961?<&%R86UE=&5R7V)A<V4@>PH@(" @=&5M<&QA=&4\='EP96YA;64@3E ^ M"B @("!N86UE9%]P87)A;65T97)?8V]M8FEN93Q.4"Q$97)I=F5D/@H@(" @ M;W!E<F%T;W(L*"!.4"!C;VYS="8@;G @*2![(')E='5R;B!N86UE9%]P87)A M;65T97)?8V]M8FEN93Q.4"Q$97)I=F5D/B@@;G L("IS=&%T:6-?8V%S=#Q$ M97)I=F5D*CXH=&AI<RD@*3L@?0I].PH*=&5M<&QA=&4@/&-L87-S($Y0+"!C M;&%S<R!297-T(#T@;FEL/@IS=')U8W0@;F%M961?<&%R86UE=&5R7V-O;6)I M;F4@.B!297-T+"!N86UE9%]P87)A;65T97)?8F%S93QN86UE9%]P87)A;65T M97)?8V]M8FEN93Q.4"Q297-T/B ^('L*(" @(&YA;65D7W!A<F%M971E<E]C M;VUB:6YE*$Y0(&-O;G-T)B!N<"P@4F5S="!C;VYS="8@<B I"B @(" Z(%)E M<W0H('(@*2P@;5]P87)A;2@@;G @*2![?0H*(" @('1Y<&5N86UE($Y0.CID M871A7W1Y<&4@8V]N<W0F(&]P97)A=&]R6UTH(&ME>7=O<F0\='EP96YA;64@ M3E Z.FED/B!K=R I(&-O;G-T('L@<F5T=7)N(&U?<&%R86U;:W==.R!]"B @ M("!U<VEN9R!297-T.CIO<&5R871O<EM=.PH@(" @=&5M<&QA=&4\='EP96YA M;64@56YK;F]W;DED/@H@(" @;FEL(&]P97)A=&]R6UTH(&ME>7=O<F0\56YK M;F]W;DED/B!K=R I(&-O;G-T('L@<F5T=7)N(&YI;"@I.R!]"@H@(" @8F]O M;"!I<U]P<F5S96YT*"!K97EW;W)D/'1Y<&5N86UE($Y0.CII9#X@*2!C;VYS M="![(')E='5R;B!T<G5E.R!]"B @("!U<VEN9R!297-T.CII<U]P<F5S96YT M.PH@(" @=&5M<&QA=&4\='EP96YA;64@2U<^"B @("!B;V]L(&ES7W!R97-E M;G0H($M7("D@8V]N<W0@>R!R971U<FX@9F%L<V4[('T@( H*(" @('5S:6YG M(&YA;65D7W!A<F%M971E<E]B87-E/&YA;65D7W!A<F%M971E<E]C;VUB:6YE M/$Y0+%)E<W0^(#XZ.F]P97)A=&]R+#L*"B @("!.4"!M7W!A<F%M.PI].PH* M=&5M<&QA=&4\='EP96YA;64@5"P@='EP96YA;64@=6YI<75E7VED/@IS=')U M8W0@;F%M961?<&%R86UE=&5R(#H@;F%M961?<&%R86UE=&5R7V)A<V4\;F%M M961?<&%R86UE=&5R/%0L('5N:7%U95]I9#X@/B!["B @("!T>7!E9&5F(%0@ M(" @(" @(" @(&1A=&%?='EP93L*(" @('1Y<&5D968@=6YI<75E7VED(" @ M:60["@H@(" @97AP;&EC:70@;F%M961?<&%R86UE=&5R*"!4(&-O;G-T)B!V M("D@.B!M7W9A;'5E*"!V("D@>WT*"B @("!4(&-O;G-T)B!O<&5R871O<EM= M*"!K97EW;W)D/'5N:7%U95]I9#X@*2!C;VYS="![(')E='5R;B!M7W9A;'5E M.R!]"B @("!B;V]L(" @("!I<U]P<F5S96YT*"!K97EW;W)D/'5N:7%U95]I M9#X@*2!C;VYS="![(')E='5R;B!T<G5E.R!]"@H@(" @5"!C;VYS="8@;5]V M86QU93L*?3L*"G1E;7!L871E/'1Y<&5N86UE('5N:7%U95]I9#X*<W1R=6-T M(&ME>7=O<F0@>PH@(" @='EP961E9B!U;FEQ=65?:60@:60["@H@(" @=&5M M<&QA=&4\='EP96YA;64@5#X*(" @(&YA;65D7W!A<F%M971E<CQ4+'5N:7%U M95]I9#X*(" @(&]P97)A=&]R/2@@5"!C;VYS="8@=" I(&-O;G-T(" @>R!R M971U<FX@;F%M961?<&%R86UE=&5R/%0L=6YI<75E7VED/B@@=" I.R!]"GT[ M"@IT96UP;&%T93QT>7!E;F%M92!4+"!T>7!E;F%M92!U;FEQ=65?:60^"G-T M<G5C="!T>7!E9%]K97EW;W)D(#H@:V5Y=V]R9#QU;FEQ=65?:60^('L*(" @ M(&YA;65D7W!A<F%M971E<CQ4+'5N:7%U95]I9#X*(" @(&]P97)A=&]R/2@@ M5"!C;VYS="8@=" I(&-O;G-T(" @>R!R971U<FX@;F%M961?<&%R86UE=&5R M/%0L=6YI<75E7VED/B@@=" I.R!]"GT["@HO+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M"B\O($5X86UP;&4Z"@HC:6YC;'5D92 \:6]S=')E86T^"B-I;F-L=61E(#QB M;V]S="]S:&%R961?<'1R+FAP<#X*"FYA;65S<&%C92!T97-T"GL*("!T>7!E M9%]K97EW;W)D/&-H87(@8V]N<W0J+'-T<G5C="!N86UE7W0^(&YA;64["B @ M='EP961?:V5Y=V]R9#QI;G0L<W1R=6-T(&EN9&5X7W0^(" @(" @("!I;F1E M>#L*("!K97EW;W)D/'-T<G5C="!V86QU95]T/B @(" @(" @(" @(" @(" @ M('9A;'5E.PH*("!T96UP;&%T93QT>7!E;F%M92!686QU951Y<&4^"B @=F]I M9"!F;V\Q*"!C:&%R(&-O;G-T*B!N+"!686QU951Y<&4@=BP@:6YT(&D@*0H@ M('L*(" @(" @<W1D.CIC;W5T(#P\(&X@/#P@)ULG(#P\(&D@/#P@(ET](B \ M/"!V(#P\('-T9#HZ96YD;#L*("!]"@H@('1E;7!L871E/&-L87-S(%!A<F%M M<SX*("!V;VED(&9O;RA087)A;7,@8V]N<W0F('!A<F%M<RD*("!["B @(" @ M(&9O;S$H('!A<F%M<UMN86UE72P@<&%R86US6W9A;'5E72P@<&%R86US6VEN M9&5X72 I.PH@('T*"B @=&5M<&QA=&4\8VQA<W,@4&%R86US/@H@('9O:60@ M8F]O*%!A<F%M<R!C;VYS="8@<&%R86US*0H@('L*(" @(" @9F]O,2@@<&%R M86US6VYA;65=+"!P87)A;7-;=F%L=65=+"!P87)A;7,N:7-?<')E<V5N="AI M;F1E>"D@/R!P87)A;7-;:6YD97A=(#H@," I.PH@('T*"B @:V5Y=V]R9#QS M=')U8W0@:6YS=&%N8V5?=#X@:6YS=&%N8V4["@H@('1E;7!L871E/'1Y<&5N M86UE(%0^"B @=F]I9"!M;V\Q*"!4*B!T("D*("!["B @(" @('-T9#HZ8V]U M=" \/" B;F]N('-H87)E9" B(#P\("IT(#P\('-T9#HZ96YD;#L*("!]"@H@ M('1E;7!L871E/'1Y<&5N86UE(%0^"B @=F]I9"!M;V\Q*"!B;V]S=#HZ<VAA M<F5D7W!T<CQ4/B!T("D*("!["B @(" @('-T9#HZ8V]U=" \/" B<VAA<F5D M("(@/#P@*G0@/#P@<W1D.CIE;F1L.PH@('T*"B @=&5M<&QA=&4\8VQA<W,@ M4&%R86US/@H@('9O:60@;6]O*%!A<F%M<R!C;VYS="8@<&%R86US*0H@('L* M(" @(" @;6]O,2@@<&%R86US6VEN<W1A;F-E72 I.PH@('T*"GT*"FEN="!M M86EN*"D*>PH@("!U<VEN9R!T97-T.CIF;V\["B @('5S:6YG('1E<W0Z.F)O M;SL*(" @=7-I;F<@=&5S=#HZ;6]O.PH@("!U<VEN9R!T97-T.CIN86UE.PH@ M("!U<VEN9R!T97-T.CIV86QU93L*(" @=7-I;F<@=&5S=#HZ:6YD97@["B @ M('5S:6YG('1E<W0Z.FEN<W1A;F-E.PH*(" @9F]O*"@@;F%M92 ](")F;V\B M+"!I;F1E>" ](# L('9A;'5E(#T@,BXU("DI.PH@("!F;V\H*"!V86QU92 ] M("=A)RP@:6YD97@@/2 Q+"!N86UE(#T@(F9O;R(@*2D["B @(&9O;R@H(&YA M;64@/2 B9&]O(BP@=F%L=64@/2 B86)C(BP@:6YD97@@/2 Q("DI.PH*(" @ M=')Y('L*(" @(" @(&9O;R@H(&YA;64@/2 B9&]O(BP@=F%L=64@/2 B86)C M(B I*3L*(" @?0H@("!C871C:"@@8VAA<B!C;VYS="H@97@@*2!["B @(" @ M("!S=&0Z.F-O=70@/#P@(D=O="!E>&-P971I;VXZ("(@/#P@97@@/#P@<W1D M.CIE;F1L.PH@("!]"@H@("!B;V\H*"!N86UE(#T@(F1O;R(L('9A;'5E(#T@ M(F%B8R(@*2D["@H@("!I;G0@:2 ](#4["@H@("!M;V\H(&EN<W1A;F-E(#T@ M)FD@*3L*(" @;6]O*"!I;G-T86YC92 ](&)O;W-T.CIS:&%R961?<'1R/&9L K;V%T/B@@;F5W(&9L;V%T*#$N,BD@*2 I.PH*(" @<F5T=7)N(# ["GT*"@`` ` end

Gennadiy Rozental wrote:
Furthermore, you have O(N) instantiations for every lookup, we have O(1).
I do not understand your code that well to contradict you, but I frankly very much doubt so.
Ok. I think I see where O(1) comes from. I've reimplemented my solution based on similar idea. Now the total size is ~60 lines and without *any* includes (see attached). And it support
1. typed keywords to support strict type checking 2. non-typed keywords to support template functions parameters 3. optional parameters and default values ( could use with runtime if without compile-time errors)
What are the other "every feature you support" but I don't?
SFINAE support, positional parameters and the fatal design mistake of treating missing required arguments as runtime errors. I'm done in this thread now. -- Daniel Wallin

1. typed keywords to support strict type checking 2. non-typed keywords to support template functions parameters 3. optional parameters and default values ( could use with runtime if without compile-time errors)
What are the other "every feature you support" but I don't?
SFINAE support,
Since you as usual did not provide an example, I may only guess that by "SFINAE support" you mean the way to implement kind of type checking. In my case I do not need that, cause I would be using typed keyword instead.
positional parameters
In what sense? The way Dave described it: positional parameters first then followed by named. In this case I believe I do support it: template<typename Params> foo( int a, string b, Params const& p ) ... It's not even necessary to have positional parameters in front (though I would always do that).
and the fatal design mistake of treating missing required arguments as runtime errors.
Well, I believe that compile time errors are at least an inconvenience and at most "fatal design mistake". Here is couple reasons why (you 'forgot' to mention any reasons for you opinion, but still) 1. Named parameter interface is assumes optional parameter in most cases. IOW we have function with variable optional number of parameters. Fact that one is not present is not an error, but a valid call. Now lets look how would you implement this function: template<Params> foo( Params const& p ) { Here you either use MP if or regular if to switch to appropriate implementation. I find regular if *much* more convenient and easier to understand and implement } 2. Default value support If optional parameter have default value it's more obvious to write just int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent. 3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile time assumes that during compiling if function invocation you have an access to function implementation. IMO this is bad assumption in general and may not be the case in a future (with different implementation if templates). Don't take me wrong there some things we do want to check at compile time. But here we talking abut function implementation details, which caller do not need to know. 4. Non-optional parameters The only 'bad' thing about runtime checking is that for required parameters fact that one is missing better be detected at compile time (Note that I don't consider runtime reports that awful either). I believe the solution could be (if necessary) to separate notion of required and optional parameters, by adding template parameter is_required to template keyword.
I'm done in this thread now.
Whatever. Good luck.
-- Daniel Wallin
Gennadiy

Gennadiy Rozental wrote:
1. typed keywords to support strict type checking 2. non-typed keywords to support template functions parameters 3. optional parameters and default values ( could use with runtime if without compile-time errors)
What are the other "every feature you support" but I don't?
SFINAE support,
Since you as usual did not provide an example, I may only guess that by "SFINAE support" you mean the way to implement kind of type checking. In my case I do not need that, cause I would be using typed keyword instead.
Just read the documentation. Or do you think enable_if<> can be replaced by just not using templates as well?
positional parameters
In what sense? The way Dave described it: positional parameters first then followed by named. In this case I believe I do support it:
Positional parameters in the sense that they can be supplied either by name or position.
and the fatal design mistake of treating missing required arguments as runtime errors.
Well, I believe that compile time errors are at least an inconvenience and at most "fatal design mistake". Here is couple reasons why (you 'forgot' to mention any reasons for you opinion, but still)
Yeah well, the reasons should be obvious for anyone that uses C++. As Rene has already pointed out in another thread.
1. Named parameter interface is assumes optional parameter in most cases. IOW we have function with variable optional number of parameters. Fact that one is not present is not an error, but a valid call. Now lets look how would you implement this function:
template<Params> foo( Params const& p ) {
Here you either use MP if or regular if to switch to appropriate implementation. I find regular if *much* more convenient and easier to understand and implement
I would use the normal way of disabling function template overloads; SFINAE.
}
2. Default value support If optional parameter have default value it's more obvious to write just
int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent.
I'm assuming you mistyped that, in which case it's spelled: int v = params[a | 8]; With our library.
3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile time assumes that during compiling if function invocation you have an access to function implementation.
No of course it doesn't assume that. The keyword parameters is part of the function *interface*, not the implementation.
IMO this is bad assumption in general and may not be the case in a future (with different implementation if templates). Don't take me wrong there some things we do want to check at compile time. But here we talking abut function implementation details, which caller do not need to know.
No, we are talking about the function interface, which the caller most likely should know about.
I'm done in this thread now.
.. I couldn't restrain myself. -- Daniel Wallin

Since you as usual did not provide an example, I may only guess that by "SFINAE support" you mean the way to implement kind of type checking. In my case I do not need that, cause I would be using typed keyword instead.
Just read the documentation.
I did. And it does not make too much sense to me. From what I gather you are using it to control overload resolution and /or to restrict types of a parameter. What overloads are you trying to resolve here: template<class A0> void foo( const A0& a0 , foo_keywords::restrict<A0>::type x = foo_keywords() ) { foo_impl(x(a0)); } template<class A0, class A1> void foo( const A0& a0, const A1& a1 , foo_keywords::restrict<A0,A1>::type x = foo_keywords() ) { foo_impl(x(a0, a1)); } As for type restriction I am using typed keywords.
Or do you think enable_if<> can be replaced by just not using templates as well?
I have no idea what you mean here. Unless you type some actual example for dummies (like me) it's all meaningless IMO.
Positional parameters in the sense that they can be supplied either by name or position.
I don't really like the idea to mix positional and named parameters this way anyway (see my other post), so wouldn't even try to implement it. Especially considering how much it cost to implement. Though you right: I do not support it as it is.
and the fatal design mistake of treating missing required arguments as runtime errors.
Well, I believe that compile time errors are at least an inconvenience and at most "fatal design mistake". Here is couple reasons why (you 'forgot' to mention any reasons for you opinion, but still)
Yeah well, the reasons should be obvious for anyone that uses C++. As Rene has already pointed out in another thread.
1. Named parameter interface is assumes optional parameter in most cases. IOW we have function with variable optional number of parameters. Fact
I use C++ (surprise, surprise) a lot. And I do not believe that absence of optional function parameter is compile time error. that
one is not present is not an error, but a valid call. Now lets look how would you implement this function:
template<Params> foo( Params const& p ) {
Here you either use MP if or regular if to switch to appropriate implementation. I find regular if *much* more convenient and easier to understand and implement
I would use the normal way of disabling function template overloads; SFINAE.
Ok. Here is an example: void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...} template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); } Above is my solution to the resolving overloads based on presence of optional named function parameter. Could you type below how would yours look like?
int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent.
I'm assuming you mistyped that, in which case it's spelled:
No, it's exactly like it supposed to be
int v = params[a | 8];
With our library.
And now compare: what is more obvious and easier to grasp?
3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile time assumes that during compiling if function invocation you have an access to function implementation.
No of course it doesn't assume that. The keyword parameters is part of the function *interface*, not the implementation.
The complete list of them - yes. But which one of them are optional, required or conditionally required is completely in function implementation domain.
IMO this is bad assumption in general and may not be the case in a future (with different implementation if templates). Don't take me wrong there some things we do want to check at compile time. But here we talking abut function implementation details, which caller do not need to know.
No, we are talking about the function interface, which the caller most likely should know about.
How are you supposed to now from 'select' function interface that timeout parameter is required iff mode parameter is WAIT? Accordingly in a point of select function invocation: select(( more =WAIT,priority=2,prefer_output=true)); You have no way to know that timeout is missing, while in following call select(( more =POOL,priority=0)); is not.
I'm done in this thread now.
.. I couldn't restrain myself.
I like this practice: during review just ignore all negative reviewers, hopefully people would missed it. Sorry, couldn't restrain myself.
-- Daniel Wallin
Gennadiy

Gennadiy Rozental wrote:
Since you as usual did not provide an example, I may only guess that by "SFINAE support" you mean the way to implement kind of type checking. In
my
case I do not need that, cause I would be using typed keyword instead.
Just read the documentation.
I did. And it does not make too much sense to me. From what I gather you are using it to control overload resolution and /or to restrict types of a parameter.
Right.
What overloads are you trying to resolve here:
template<class A0> void foo( const A0& a0 , foo_keywords::restrict<A0>::type x = foo_keywords() ) { foo_impl(x(a0)); }
template<class A0, class A1> void foo( const A0& a0, const A1& a1 , foo_keywords::restrict<A0,A1>::type x = foo_keywords() ) { foo_impl(x(a0, a1)); }
There are no more overloads here. But foo is only enabled when the "name" parameter is convertible to char const*: struct foo_keywords : boost::keywords< boost::named_param< name_t , mpl::false_ , is_convertible<mpl::_, const char*> > , value_t > {};
As for type restriction I am using typed keywords.
But that's not enough! It's too naive. What if you want a function overload: template<class Value> void f(Value); Where Value is restricted to types that are Movable, detectable with is_movable<>. How would you do this? And again, the restrictions should **NOT** be part of the keywords. Keywords are naturally reusable components that can be shared by multiple functions. This has been pointed out several times in these discussions.
and the fatal design mistake of treating missing required arguments as runtime errors.
Well, I believe that compile time errors are at least an inconvenience
and
at most "fatal design mistake". Here is couple reasons why (you 'forgot'
to
mention any reasons for you opinion, but still)
Yeah well, the reasons should be obvious for anyone that uses C++. As Rene has already pointed out in another thread.
I use C++ (surprise, surprise) a lot. And I do not believe that absence of optional function parameter is compile time error.
It's not optional, it's required. That's the whole point. Did you consider Rene's post?
1. Named parameter interface is assumes optional parameter in most
cases.
IOW we have function with variable optional number of parameters. Fact
that
one is not present is not an error, but a valid call. Now lets look how would you implement this function:
template<Params> foo( Params const& p ) {
Here you either use MP if or regular if to switch to appropriate implementation. I find regular if *much* more convenient and easier to understand and implement
I would use the normal way of disabling function template overloads; SFINAE.
Ok. Here is an example:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
Above is my solution to the resolving overloads based on presence of optional named function parameter. Could you type below how would yours look like?
Actually, we can't do that with the overload restrictions. I guess we could support it, and maybe we should.. Anyway, the code you posted is valid with our library as well, if that you suppress the compilation error by supplying a default value for i2: template<typename Params> void foo( Params const& p ) { if(has(p, i2)) foo_impl(p[i1], p[i2 | 0]); else foo_impl(p[i1]); } has() isn't part of the library: struct nil_ {}; bool has_impl(nil_) { return false; } template<class T> bool has_impl(T const&) { return true; } template<class P, class T> bool has(P const& args, T const& tag) { return has_impl(args[tag | nil_()]); } This solution is obviously flawed though, since in general you can't be assumed to be able to change foo() to account for every possible overload.
int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent.
I'm assuming you mistyped that, in which case it's spelled:
No, it's exactly like it supposed to be
If the user has supplied parameter "a", set v to parameter s, otherwise set it to 8?
int v = params[a | 8];
With our library.
And now compare: what is more obvious and easier to grasp?
Your version is easier to grasp until you have learned the DSL. But the cost of it is that your code won't work in a lot of cases. For instance, the default value expression always has to be compiled. And of course, as said before, missing a required parameter will cause a runtime error.
3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile
time
assumes that during compiling if function invocation you have an access
to
function implementation.
No of course it doesn't assume that. The keyword parameters is part of the function *interface*, not the implementation.
The complete list of them - yes. But which one of them are optional, required or conditionally required is completely in function implementation domain.
Really? Is the parameter defaults also an implementation detail? As a user, how am I suppose to use your functions if I don't know about these things?
IMO this is bad assumption in general and may not be the case in a future (with different implementation if templates).
Don't
take me wrong there some things we do want to check at compile time. But here we talking abut function implementation details, which caller do
not
need to know.
No, we are talking about the function interface, which the caller most likely should know about.
How are you supposed to now from 'select' function interface that timeout parameter is required iff mode parameter is WAIT? Accordingly in a point of select function invocation:
select(( more =WAIT,priority=2,prefer_output=true));
You have no way to know that timeout is missing, while in following call
select(( more =POOL,priority=0));
is not.
Why? It's a simple precondition that might even be enforced at compile time with our library if you want to.
I'm done in this thread now.
.. I couldn't restrain myself.
I like this practice: during review just ignore all negative reviewers, hopefully people would missed it. Sorry, couldn't restrain myself.
I have read and considered everything you have written. -- Daniel Wallin

Aaron W. LaFramboise wrote:
Daniel Wallin wrote:
Your version is easier to grasp until you have learned the DSL. But the
What is the DSL?
args[keyword | default] http://en.wikipedia.org/wiki/Domain-specific_language -- Daniel Wallin

What overloads are you trying to resolve here:
template<class A0> void foo( const A0& a0 , foo_keywords::restrict<A0>::type x = foo_keywords() ) { foo_impl(x(a0)); }
template<class A0, class A1> void foo( const A0& a0, const A1& a1 , foo_keywords::restrict<A0,A1>::type x = foo_keywords() ) { foo_impl(x(a0, a1)); }
There are no more overloads here. But foo is only enabled when the "name" parameter is convertible to char const*:
Wait, this is an exact copy of an example you have in "controlling overload resolution" section. Any why two functions then? So can you gove me an example of "controlling overload resolution" feature?
struct foo_keywords : boost::keywords< boost::named_param< name_t , mpl::false_ , is_convertible<mpl::_, const char*> > , value_t > {};
As for type restriction I am using typed keywords.
But that's not enough! It's too naive. What if you want a function overload:
template<class Value> void f(Value);
Where Value is restricted to types that are Movable, detectable with is_movable<>.
How would you do this?
First of all this is comparatevly rarely needed. Accordingly I do not see a reasons to supply library solution for this problem. Whould I ever need something like this, I would do: template<typename Value> enable_if<Value is movable,void> foo_impl( Value const&, std::string name, Mymode mode ) { } template<typename Params> void foo(Params const& p) { foo_impl( p[value], p[name], p[mode] ); } value above is typelees keyword in my terminology. And no need to mix everything into one bowl.
And again, the restrictions should **NOT** be part of the keywords. Keywords are naturally reusable components that can be shared by multiple functions. This has been pointed out several times in these discussions.
It depends IMO. I personally in most cases prefer keyword to be typed. My solution also support typeless keywords if you like so. See above for the possible way to implement a restrictions.
I use C++ (surprise, surprise) a lot. And I do not believe that absence of optional function parameter is compile time error.
It's not optional, it's required. That's the whole point. Did you consider Rene's post?
Even though I don't see as a major advantage (you as a programmer will detect and fix this issue in any case, would it be compile time or runtime error), my latest attempt does produce a compile time error in case of missing required parameter (while it does not do that in case of optional)
I would use the normal way of disabling function template overloads; SFINAE.
Ok. Here is an example:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
Above is my solution to the resolving overloads based on presence of optional named function parameter. Could you type below how would yours look like?
Actually, we can't do that with the overload restrictions. I guess we could support it, and maybe we should..
Anyway, the code you posted is valid with our library as well, if that you suppress the compilation error by supplying a default value for i2:
[solution skipped] This is not exactly the same thing, and clear source of confusion.
This solution is obviously flawed though, since in general you can't be assumed to be able to change foo() to account for every possible overload.
Ok. So what is your solution to the problem of supplying single named parameter based interface for dynamically sized series of functions with different actual number of arguments?
int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent.
I'm assuming you mistyped that, in which case it's spelled:
No, it's exactly like it supposed to be
If the user has supplied parameter "a", set v to parameter s, otherwise set it to 8?
Yes. It should be the same keyword of course.
int v = params[a | 8];
With our library.
And now compare: what is more obvious and easier to grasp?
Your version is easier to grasp until you have learned the DSL.
But the cost of it is that your code won't work in a lot of cases. For instance, the default value expression always has to be compiled.
Why is that? Why Couldn't I do the same as what you are doing? int v = params.has(a) ? params[a] : get_a_default_value(); It's even easier since I do not need to wrap it into bind call.
And of course, as said before, missing a required parameter will cause a runtime error.
Compile time error
3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile
time
assumes that during compiling if function invocation you have an access
to
function implementation.
No of course it doesn't assume that. The keyword parameters is part of the function *interface*, not the implementation.
The complete list of them - yes. But which one of them are optional, required or conditionally required is completely in function implementation domain.
Really? Is the parameter defaults also an implementation detail? As a user, how am I suppose to use your functions if I don't know about these things?
Yes. I inclined to think about function parameter default values more in terms of implementation details rather than part of interface. You as a function user shouldn't based your decisions on the default value for the parameter: you have value for this parameter - you supply it. You don't - function deals with it itself. This is especially true since in many , many cases you just couldn't put default value into function declaration: int foo( int a, int b = a ) {...} What we do instead is somehow mimic similar behavior: int foo( int a, int b = -1 ) { if( b = -1 ) b = a; } So what default value -1 gives you as a function caller?
How are you supposed to now from 'select' function interface that timeout parameter is required iff mode parameter is WAIT? Accordingly in a point of select function invocation:
select(( mode =WAIT,priority=2,prefer_output=true));
You have no way to know that timeout is missing, while in following call
select(( mode =POOL,priority=0));
is not.
Why? It's a simple precondition that might even be enforced at compile time with our library if you want to.
How? I would like to see it. I would like to see you to produce compile time error based on runtime value of the variable. And let then compare it with how my solution would look like: int select( Params const& p ) { switch( p[mode] ) { case WAIT: return select_impl( p[priority], p[prefer_output], p[timeout]); case BLOCK: return select_impl( p[priority], p[prefer_output] ); case POOL: return select_impl( p[priority], p[prefer_output], TimeValue( 0,0 ) ); } }
Daniel Wallin
Gennadiy

Gennadiy Rozental wrote:
What overloads are you trying to resolve here:
template<class A0> void foo( const A0& a0 , foo_keywords::restrict<A0>::type x = foo_keywords() ) { foo_impl(x(a0)); }
template<class A0, class A1> void foo( const A0& a0, const A1& a1 , foo_keywords::restrict<A0,A1>::type x = foo_keywords() ) { foo_impl(x(a0, a1)); }
There are no more overloads here. But foo is only enabled when the "name" parameter is convertible to char const*:
Wait, this is an exact copy of an example you have in "controlling overload resolution" section. Any why two functions then?
I'm sorry, I don't know what that means.
So can you gove me an example of "controlling overload resolution" feature?
I just did. foo is enabled only when 'name' is convertible to char const*.
As for type restriction I am using typed keywords.
But that's not enough! It's too naive. What if you want a function overload:
template<class Value> void f(Value);
Where Value is restricted to types that are Movable, detectable with is_movable<>.
How would you do this?
First of all this is comparatevly rarely needed. Accordingly I do not see a reasons to supply library solution for this problem.
So we shouldn't care about this use case? Why? To reduce the number of lines of code in the implementation?
Whould I ever need something like this, I would do:
template<typename Value> enable_if<Value is movable,void> foo_impl( Value const&, std::string name, Mymode mode ) { }
template<typename Params> void foo(Params const& p) { foo_impl( p[value], p[name], p[mode] ); }
value above is typelees keyword in my terminology. And no need to mix everything into one bowl.
But again, you don't generally have the ability to have a universal foo() overload that handles the dispatching. You want one for every overload.
Actually, we can't do that with the overload restrictions. I guess we could support it, and maybe we should..
Anyway, the code you posted is valid with our library as well, if that you suppress the compilation error by supplying a default value for i2:
[solution skipped]
This is not exactly the same thing, and clear source of confusion.
Really? What's the difference?
This solution is obviously flawed though, since in general you can't be assumed to be able to change foo() to account for every possible overload.
Ok. So what is your solution to the problem of supplying single named parameter based interface for dynamically sized series of functions with different actual number of arguments?
I would add something to the library to control overload resolution for this case with SFINAE.
int v = params[a | 8];
With our library.
And now compare: what is more obvious and easier to grasp?
Your version is easier to grasp until you have learned the DSL.
But the cost of it is that your code won't work in a lot of cases. For instance, the default value expression always has to be compiled.
Why is that? Why Couldn't I do the same as what you are doing?
int v = params.has(a) ? params[a] : get_a_default_value();
It's even easier since I do not need to wrap it into bind call.
No, because get_a_default_value() has to compile. Our defaults can be lazily evaluated, and only compiled when needed.
Really? Is the parameter defaults also an implementation detail? As a user, how am I suppose to use your functions if I don't know about these things?
Yes. I inclined to think about function parameter default values more in terms of implementation details rather than part of interface. You as a function user shouldn't based your decisions on the default value for the parameter: you have value for this parameter - you supply it. You don't - function deals with it itself. This is especially true since in many , many cases you just couldn't put default value into function declaration:
int foo( int a, int b = a ) {...}
What we do instead is somehow mimic similar behavior:
int foo( int a, int b = -1 ) { if( b = -1 ) b = a; }
So what default value -1 gives you as a function caller?
The value of 'a'? What you were arguing here however is that it shouldn't even be part of the interface whether 'b' has a default value or is a required parameter.
How are you supposed to now from 'select' function interface that
timeout
parameter is required iff mode parameter is WAIT? Accordingly in a point
of
select function invocation:
select(( mode =WAIT,priority=2,prefer_output=true));
You have no way to know that timeout is missing, while in following call
select(( mode =POOL,priority=0));
is not.
Why? It's a simple precondition that might even be enforced at compile time with our library if you want to.
How? I would like to see it. I would like to see you to produce compile time error based on runtime value of the variable.
Of course I can't produce compile time errors based on runtime values, but who said anything about mode being a runtime value? The modes could just as well be tag types here, in which case it's trivial. template<class P> int select_impl(wait_t, P const& args) .. template<class P> int select_impl(block_t, P const& args) .. template<class P> int select_impl(pool_t, P const& args) .. template<class P> int select(P const& args) { return select_impl(args[mode], args); } -- Daniel Wallin

Wait, this is an exact copy of an example you have in "controlling overload resolution" section. Any why two functions then?
I'm sorry, I don't know what that means.
So can you gove me an example of "controlling overload resolution" feature?
I just did. foo is enabled only when 'name' is convertible to char const*.
No. this is an example of type restriction. Overload resolution assimes at least 2 overloads, doesn't it?
First of all this is comparatevly rarely needed. Accordingly I do not see a reasons to supply library solution for this problem.
So we shouldn't care about this use case? Why? To reduce the number of lines of code in the implementation?
No. I just don't think it belong to this library at all. Especially if it's easier to implement without library.
Whould I ever need something like this, I would do:
template<typename Value> enable_if<Value is movable,void> foo_impl( Value const&, std::string name, Mymode mode ) { }
template<typename Params> void foo(Params const& p) { foo_impl( p[value], p[name], p[mode] ); }
value above is typelees keyword in my terminology. And no need to mix everything into one bowl.
But again, you don't generally have the ability to have a universal foo() overload that handles the dispatching. You want one for every overload.
You keep pressing that there maybe more that one foo. Why would I want to do this? Could you give an example? In my POV I onlt need one foo(Params const& p ) since it automatically cover all possible invokcation of function foo.
This is not exactly the same thing, and clear source of confusion.
Really? What's the difference?
Difference is this 8 out of 10 developers would ask where this 0 comes from? And what does it mean? 2 out of 10 wouldn't understant this code at all.
Ok. So what is your solution to the problem of supplying single named parameter based interface for dynamically sized series of functions with different actual number of arguments?
I would add something to the library to control overload resolution for this case with SFINAE.
I am getting an impression that you don't have even vague idea how would it look like. Could you come up at least with some pseudo code?
Why is that? Why Couldn't I do the same as what you are doing?
int v = params.has(a) ? params[a] : get_a_default_value();
It's even easier since I do not need to wrap it into bind call.
No, because get_a_default_value() has to compile. Our defaults can be lazily evaluated, and only compiled when needed.
Really? Is the parameter defaults also an implementation detail? As a user, how am I suppose to use your functions if I don't know about these things?
Yes. I inclined to think about function parameter default values more in terms of implementation details rather than part of interface. You as a function user shouldn't based your decisions on the default value for
Here is your code: double value_default() { return 666.222; } template<class Params> int f_impl(const Params& p) { p[tester]( p[name], p[value || boost::bind(&value_default) ] ); } Here is mine: double value_default() { return 666.222; } template<class Params> int f_impl(const Params& p) { p[tester]( p[name], p.has(value) ? p[value] : value_default() ); } In both cases default_value() needs to be compiled. Why my syntax is way better IMO. the
parameter: you have value for this parameter - you supply it. You don't - function deals with it itself. This is especially true since in many , many cases you just couldn't put default value into function declaration:
int foo( int a, int b = a ) {...}
What we do instead is somehow mimic similar behavior:
int foo( int a, int b = -1 ) { if( b = -1 ) b = a; }
So what default value -1 gives you as a function caller?
The value of 'a'?
And how caller should know that? And most importantly why?
What you were arguing here however is that it shouldn't even be part of the interface whether 'b' has a default value or is a required parameter.
In legacy C+ there are areseveral ways to make b "optional" .., int b = 2 ..., int b = invalid_value ..., int* b ..., optional<int> b = optional<int>() The only thing that is important is the fact that b is optional. This is interface part. The default value (if needed) is implementation detail. In my solution I mark keywords whether or not they name optional or requied parameters.
How? I would like to see it. I would like to see you to produce compile time error based on runtime value of the variable.
Of course I can't produce compile time errors based on runtime values, but who said anything about mode being a runtime value? The modes could just as well be tag types here, in which case it's trivial.
In many cases it's not acceptable.
template<class P> int select_impl(wait_t, P const& args) ..
template<class P> int select_impl(block_t, P const& args) ..
template<class P> int select_impl(pool_t, P const& args) ..
template<class P> int select(P const& args) { return select_impl(args[mode], args); }
Hey! Where is optional timeout handling? You code wouldn't compile if timeut is missing.
-- Daniel Wallin
Gennadiy

4. Non-optional parameters
The only 'bad' thing about runtime checking is that for required parameters fact that one is missing better be detected at compile time (Note that I don't consider runtime reports that awful either). I believe the solution could be (if necessary) to separate notion of required and optional parameters, by adding template parameter is_required to template keyword.
Just for the hell of it, here is the version (65 lines) that gives compile time errors on required parameters and runtime time errors for optional. template<typename NP1,typename NP2> struct named_parameter_combine; template<typename T, typename unique_id> struct named_parameter; template<typename unique_id,bool optional> struct keyword; struct nil { template<typename T> operator T() { throw "access_to_invalid_parameter"; return *(T*)0; } }; template<typename Derived> struct named_parameter_base { template<typename NP> named_parameter_combine<NP,Derived> operator,( NP const& np ) { return named_parameter_combine<NP,Derived>( np, *static_cast<Derived*>(this) ); } }; template <class NP, class Rest = nil> struct named_parameter_combine : Rest, named_parameter_base<named_parameter_combine<NP,Rest> > { named_parameter_combine(NP const& np, Rest const& r ) : Rest( r ), m_param( np ) {} typename NP::data_type const& operator[]( keyword<typename NP::id,true> kw ) const { return m_param[kw]; } typename NP::data_type const& operator[]( keyword<typename NP::id,false> kw ) const { return m_param[kw]; } using Rest::operator[]; template<typename UnknownId> nil operator[]( keyword<UnknownId,true> kw ) const { return nil(); } bool is_present( keyword<typename NP::id,true> ) const { return true; } using Rest::is_present; template<typename UnknownId> bool is_present( keyword<UnknownId,true> ) const { return false; } using named_parameter_base<named_parameter_combine<NP,Rest>
::operator,;
NP m_param; }; template<typename T, typename unique_id> struct named_parameter : named_parameter_base<named_parameter<T, unique_id>
{ typedef T data_type; typedef unique_id id;
explicit named_parameter( T const& v ) : m_value( v ) {} T const& operator[]( keyword<unique_id,true> ) const { return m_value; } T const& operator[]( keyword<unique_id,false> ) const { return m_value; } bool is_present( keyword<unique_id,true> ) const { return true; } T const& m_value; }; template<typename unique_id,bool optional = true> struct keyword { typedef unique_id id; template<typename T> named_parameter<T,unique_id> operator=( T const& t ) const { return named_parameter<T,unique_id>( t ); } }; template<typename T, typename unique_id,bool optional = true> struct typed_keyword : keyword<unique_id,optional> { named_parameter<T,unique_id> operator=( T const& t ) const { return named_parameter<T,unique_id>( t ); } }; Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
Just for the hell of it, here is the version (65 lines) that gives compile time errors on required parameters and runtime time errors for optional.
template<typename NP1,typename NP2> struct named_parameter_combine; template<typename T, typename unique_id> struct named_parameter; template<typename unique_id,bool optional> struct keyword;
struct nil { template<typename T> operator T() { throw "access_to_invalid_parameter"; return *(T*)0; } };
It's easy to pack lots of stuff into few lines when you use a dense, illgegible coding style with really long lines of source and unaligned braces. Using our coding style it's 122 lines without namespaces, comments, include guards, or copyright notices. Not to mention which it sacrifices compile-time type safety for runtime checks. Anyone can throw together a less-capable prototype and come out with smaller code. I don't think it proves much. This is the first review I've seen where the focus on implementation details is so intense. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

It's easy to pack lots of stuff into few lines when you use a dense, illgegible coding style with really long lines of source and unaligned braces. Using our coding style it's 122 lines without namespaces, comments, include guards, or copyright notices.
I hoped to see not only comments on my coding style (which is BTW not that dense) but more technical one. Note though that even in your format it still 5 times smaller then gcc version of your code.
Not to mention which it sacrifices compile-time type safety for runtime checks.
That is not true. version you refer to does produce compile time errors facing missing required parameter.
Anyone can throw together a less-capable prototype and come out with smaller code. I don't think it proves much. This is the first review I've seen where the focus on implementation details is so intense.
I hoped you would admit that differences in my approach are way beyond "implementation details" (though I do not really like the implementation either). I differ in (among other things): 1. parameter type enforcing 2. default value support 3. option parameter support 4. Unlimited number of parameters support IOW in most major design decisions.
-- Dave Abrahams
Regards, Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
It's easy to pack lots of stuff into few lines when you use a dense, illgegible coding style with really long lines of source and unaligned braces. Using our coding style it's 122 lines without namespaces, comments, include guards, or copyright notices.
I hoped to see not only comments on my coding style (which is BTW not that dense) but more technical one.
As long as you're counting lines of code, coding style is relevant.
Note though that even in your format it still 5 times smaller then gcc version of your code.
No doubt.
That is not true. version you refer to does produce compile time errors facing missing required parameter.
Oh, sorry, I must've missed that.
Anyone can throw together a less-capable prototype and come out with smaller code. I don't think it proves much. This is the first review I've seen where the focus on implementation details is so intense.
I hoped you would admit that differences in my approach are way beyond "implementation details" (though I do not really like the implementation either). I differ in (among other things):
1. parameter type enforcing
Check. You provide a simpler and less-capable interface. Of course it would be easy to add a simple and less-capable interface on top of our general one.
2. default value support
Details, please? Please show the differences (I've clearly lost track of this thread).
3. option parameter support
Details, please?
4. Unlimited number of parameters support
If I understand what you're saying, no you don't. Don't forget, we have the overloaded comma operator. If I don't understand what you're saying: details, please? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

1. parameter type enforcing
Check. You provide a simpler and less-capable interface. Of course it would be easy to add a simple and less-capable interface on top of our general one.
Could you please ground you statement about "less-capable". With specific examples. If you mean something amoung the lines "is_movable" check. Look at my responce here: http://lists.boost.org/MailArchives/boost/msg75147.php
2. default value support
Details, please? Please show the differences (I've clearly lost track of this thread).
3. option parameter support
template<typename Params> void foo( Params const& p ) { you interface int ind = p[index | 0 ]; my interface int ind = p.has(index) ? p[index] : 0; } optional actually. Sorry
Details, please?
From other thread:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
4. Unlimited number of parameters support
If I understand what you're saying, no you don't.
Why? I could have as many parameters to function as I want since I do not try to combine under the hood of single keywords structure.
Don't forget, we have the overloaded comma operator.
Don't you still need to use keywords structure? Doesn't it has limited arity? If you don't, which features wouldn't be accessible (without keywords structure)?
If I don't understand what you're saying: details, please?
-- Dave Abrahams
Regards, Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
1. parameter type enforcing
Check. You provide a simpler and less-capable interface. Of course it would be easy to add a simple and less-capable interface on top of our general one.
Could you please ground you statement about "less-capable". With specific examples. If you mean something amoung the lines "is_movable" check.
I do.
Look at my responce here:
I saw that. You are basically saying the capability isn't important. We can agree or disagree over that point, but the fact is that the interface you support is still less-capable. I'm trying to bring this back to objective reality.
2. default value support
Details, please? Please show the differences (I've clearly lost track of this thread).
template<typename Params> void foo( Params const& p ) { you interface int ind = p[index | 0 ]; my interface int ind = p.has(index) ? p[index] : 0; }
If that's your interface, I don't see how the following statement of yours can also be true:
version you refer to does produce compile time errors facing missing required parameter.
Meaning that if there's no default for index, in your code: int ind = p[index]; will still compile.
3. option parameter support optional actually. Sorry
Details, please?
From other thread:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
I'm not sure what you're saying. With the addition of "has" functionality (which we've long ago agreed should be added), you could do this with our design. We can agree or disagree that this approach is a good idea or not, but the fact remains that your design has no support for non-intrusive overloading (e.g. via ADL).
4. Unlimited number of parameters support
If I understand what you're saying, no you don't.
Why? I could have as many parameters to function as I want since I do not try to combine under the hood of single keywords structure.
I understand that. I'm saying you don't have a new capability here.
Don't forget, we have the overloaded comma operator.
Don't you still need to use keywords structure?
You don't have to specify it up front unless you want to do overload resolution control. Okay, thanks, I think I understand your value decisions and design choices here. I was asking because I was concerned that your simpler design might have been an improvement, but I'm now confident we got closer to the sweet spot in the design space, at least from my point of view. Cheers, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

1. parameter type enforcing
Check. You provide a simpler and less-capable interface. Of course it would be easy to add a simple and less-capable interface on top of our general one.
Could you please ground you statement about "less-capable". With specific examples. If you mean something amoung the lines "is_movable" check.
I do.
Look at my responce here:
I saw that. You are basically saying the capability isn't important. We can agree or disagree over that point, but the fact is that the interface you support is still less-capable. I'm trying to bring this back to objective reality.
And I am still disagree. Why is that interface less-capable if I could implement the same logic as with even less keystrokes. Just because you put something into library header doesn't make it more powerfull. It should really bring some advantages and simplify (enhance usebility) function implementation in user's code.
2. default value support
Details, please? Please show the differences (I've clearly lost track of this thread).
template<typename Params> void foo( Params const& p ) { you interface int ind = p[index | 0 ]; my interface int ind = p.has(index) ? p[index] : 0; }
If that's your interface, I don't see how the following statement of yours can also be true:
version you refer to does produce compile time errors facing missing required parameter.
Meaning that if there's no default for index, in your code:
int ind = p[index]; will still compile.
If parameter is *required*, you will get a compile time error . It it optional you may (it's not nessesary though) define default value. Any access to omitted optional parameter would produce runtime error.
3. option parameter support optional actually. Sorry
Details, please?
From other thread:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
I'm not sure what you're saying. With the addition of "has" functionality (which we've long ago agreed should be added), you could do this with our design.
No you couldn't . Above wouldn't compile.
We can agree or disagree that this approach is a good idea or not, but the fact remains that your design has no support for non-intrusive overloading (e.g. via ADL).
Could you show me an example of "non-intrusive overloading" and how you design supports it.
4. Unlimited number of parameters support
If I understand what you're saying, no you don't.
Why? I could have as many parameters to function as I want since I do not try to combine under the hood of single keywords structure.
I understand that. I'm saying you don't have a new capability here.
Don't forget, we have the overloaded comma operator.
Don't you still need to use keywords structure?
You don't have to specify it up front unless you want to do overload resolution control.
What about type restrictions?
Okay, thanks, I think I understand your value decisions and design choices here. I was asking because I was concerned that your simpler design might have been an improvement, but I'm now confident we got closer to the sweet spot in the design space, at least from my point of view.
IMO you are yet to show single example that have prove a real advantage of you design. I showed several. All I sew from you so far in not convincing. It's good, that you confident though.
Cheers, -- Dave Abrahams
Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
1. parameter type enforcing
Check. You provide a simpler and less-capable interface. Of course it would be easy to add a simple and less-capable interface on top of our general one.
Could you please ground you statement about "less-capable". With specific examples. If you mean something amoung the lines "is_movable" check.
I do.
Look at my responce here:
I saw that. You are basically saying the capability isn't important. We can agree or disagree over that point, but the fact is that the interface you support is still less-capable. I'm trying to bring this back to objective reality.
And I am still disagree. Why is that interface less-capable if I could implement the same logic as with even less keystrokes.
You can't implement the same compile-time logic with less keystrokes. It's less capable because our design has a capability that yours doesn't. Not a matter of opinion, just a fact.
Just because you put something into library header doesn't make it more powerfull.
I didn't say it was more powerful. I said it was more capable.
It should really bring some advantages and simplify (enhance usebility) function implementation in user's code.
Maybe so. Whether or not the advantages I think the capability brings are real or not appears to be a matter of opinion. The fact that the capability is in our design and not in yours is, well... a fact.
2. default value support
Details, please? Please show the differences (I've clearly lost track of this thread).
template<typename Params> void foo( Params const& p ) { you interface int ind = p[index | 0 ]; my interface int ind = p.has(index) ? p[index] : 0; }
If that's your interface, I don't see how the following statement of yours can also be true:
version you refer to does produce compile time errors facing missing required parameter.
Meaning that if there's no default for index, in your code:
int ind = p[index]; will still compile.
If parameter is *required*, you will get a compile time error . It it optional you may (it's not nessesary though) define default value. Any access to omitted optional parameter would produce runtime error.
Ah, I understand, now. Thanks. In that case my original statement about your design that "it sacrifices compile-time type safety for runtime checks" is in fact true.
3. option parameter support optional actually. Sorry
Details, please?
From other thread:
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
I'm not sure what you're saying. With the addition of "has" functionality (which we've long ago agreed should be added), you could do this with our design.
No you couldn't. Above wouldn't compile.
Mmmm.... why not?
We can agree or disagree that this approach is a good idea or not, but the fact remains that your design has no support for non-intrusive overloading (e.g. via ADL).
Could you show me an example of "non-intrusive overloading" and how you design supports it.
Sorry, like Fermat I don't have time/space to write it down here ;-). In shorthand, it's the ability to add new overloads of a top-level (public) function template that uses named parameters without changing the implementation of that function.
4. Unlimited number of parameters support
If I understand what you're saying, no you don't.
Why? I could have as many parameters to function as I want since I do not try to combine under the hood of single keywords structure.
I understand that. I'm saying you don't have a new capability here.
Don't forget, we have the overloaded comma operator.
Don't you still need to use keywords structure?
You don't have to specify it up front unless you want to do overload resolution control.
What about type restrictions?
If you want them, you specify it. So maybe you have a way to specify type restrictions without building a keywords structure, although you do require people to bind the type restriction into the keyword itself. I admit that is a design difference.
Okay, thanks, I think I understand your value decisions and design choices here. I was asking because I was concerned that your simpler design might have been an improvement, but I'm now confident we got closer to the sweet spot in the design space, at least from my point of view.
IMO you are yet to show single example that have prove a real advantage of you design.
I am not out to prove it to you. I never try to change the opinion of someone whose mind is already made up.
I showed several. All I sew from you so far in not convincing.
:^). That the examples I have shown don't convince you is not surprising. Likewise, none of the examples you've shown are convincing to me, although at the beginning of this exchange I was prepared to believe you had done something worthy of attention.
It's good, that you confident though.
Your sarcasm is unwarranted. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

You can't implement the same compile-time logic with less keystrokes. It's less capable because our design has a capability that yours doesn't. Not a matter of opinion, just a fact.
The only fact here is that you are making that statement. Let's take you "more-capable" interface and implement solution for simple problem. Let then take my interface and implement the solution for the same problem using my "less-capable" interface. Let than compare which variant is easier and shorter. And that would be *the fact* (it's still matter of taste/preference, but I hope we will be able to see it clearly). Until that time you statement: "You can't implement the same compile-time logic with less keystrokes" *is* a matter of opinion and not a fact.
If parameter is *required*, you will get a compile time error . If it's optional you may (it's not necessary though) define default value. Any access to omitted optional parameter would produce runtime error.
Ah, I understand, now. Thanks. In that case my original statement about your design that "it sacrifices compile-time type safety for runtime checks" is in fact true.
I may say the same thing, but pressing different points: your design sacrifices flexibility and usability for ... compile time switch of function implementation. My design based on a two facts: 1. it's perfectly ok to omit optional parameter in function invocation 2. If parameter is optional why invocation should fail to compile if it's missing? 3. it's ok to switch function implementation at runtime based on presence/absence of function parameter
void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...}
template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); }
No you couldn't. Above wouldn't compile.
Mmmm.... why not?
Because p[i2] fails to compile if i2 is missing.
Could you show me an example of "non-intrusive overloading" and how you design supports it.
Sorry, like Fermat I don't have time/space to write it down here ;-).
Not even small example? Pseudocode? Pity. I would be much more easier to discuss the differences.
In shorthand, it's the ability to add new overloads of a top-level (public) function template that uses named parameters without changing the implementation of that function.
Do you mean: without need to change other overloads of the same function? You see, it's difficult for me to imagine this situation since in a majority of the cases I would be using *single* public function: foo( Params const& ) that cover all possible combinations of parameters. If you could just explain (give an example) when I would need more.
4. Unlimited number of parameters support What about type restrictions?
If you want them, you specify it.
IOW library wouldn't be able to provide automatic support for this.
So maybe you have a way to specify type restrictions without building a keywords structure, although you do require people to bind the type restriction into the keyword itself. I admit that is a design difference.
So you solution either force limit on number of parameter or does not provide automatic type checking. Is this right?
IMO you are yet to show single example that have prove a real advantage of you design.
I am not out to prove it to you. I never try to change the opinion of someone whose mind is already made up.
That the examples I have shown don't convince you is not surprising.
Did you? Did I missed them?
It's good, that you confident though.
Your sarcasm is unwarranted.
Well. Since you believe you are allowed to state "I am confident, that I am right", I believe I am allowed to be a bit sarcastic (especially since I feel that you statement does not have enough foundations)
-- Dave Abrahams

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
Your sarcasm is unwarranted.
Well. Since you believe you are allowed to state "I am confident, that I am right", I believe I am allowed to be a bit sarcastic (especially since I feel that you statement does not have enough foundations)
Go back and read the statement you're referring to again. I didn't say I was confident that I am right. I am confident that we got closer to what is (from my point of view -- I used that qualification before) the design sweet spot. Please try to take a more productive approach to these discussions. This isn't a contest. I was only engaging you here because I was interested in what your design ideas might have to offer. I am trying to keep my eye on technical issues, but the more aggressively you approach the conversation, the less receptive I find myself becoming. Cheers, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Gennadiy Rozental wrote:
You can't implement the same compile-time logic with less keystrokes. It's less capable because our design has a capability that yours doesn't. Not a matter of opinion, just a fact.
The only fact here is that you are making that statement. Let's take you "more-capable" interface and implement solution for simple problem. Let then take my interface and implement the solution for the same problem using my "less-capable" interface. Let than compare which variant is easier and shorter. And that would be *the fact* (it's still matter of taste/preference, but I hope we will be able to see it clearly). Until that time you statement:
"You can't implement the same compile-time logic with less keystrokes"
*is* a matter of opinion and not a fact.
Fair enough. So, please show us your code that "implement the same logic as with even less keystrokes". But please remember: less keystrokes doesn't mean better code. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Since you as usual did not provide an example, I may only guess that by "SFINAE support" you mean the way to implement kind of type checking. In my case I do not need that, cause I would be using typed keyword instead.
Just read the documentation.
I did. And it does not make too much sense to me. From what I gather you are using it to control overload resolution and /or to restrict types of a parameter. What overloads are you trying to resolve here: template<class A0> void foo( const A0& a0 , foo_keywords::restrict<A0>::type x = foo_keywords() ) { foo_impl(x(a0)); } template<class A0, class A1> void foo( const A0& a0, const A1& a1 , foo_keywords::restrict<A0,A1>::type x = foo_keywords() ) { foo_impl(x(a0, a1)); } As for type restriction I am using typed keywords.
Or do you think enable_if<> can be replaced by just not using templates as well?
I have no idea what you mean here. Unless you type some actual example for dummies (like me) it's all meaningless IMO.
Positional parameters in the sense that they can be supplied either by name or position.
I don't really like the idea to mix positional and named parameters this way anyway (see my other post), so wouldn't even try to implement it. Especially considering how much it cost to implement. Though you right: I do not support it as it is.
and the fatal design mistake of treating missing required arguments as runtime errors.
Well, I believe that compile time errors are at least an inconvenience and at most "fatal design mistake". Here is couple reasons why (you 'forgot' to mention any reasons for you opinion, but still)
Yeah well, the reasons should be obvious for anyone that uses C++. As Rene has already pointed out in another thread.
1. Named parameter interface is assumes optional parameter in most cases. IOW we have function with variable optional number of parameters. Fact
I use C++ (surprise, surprise) a lot. And I do not believe that absence of optional function parameter is compile time error. that
one is not present is not an error, but a valid call. Now lets look how would you implement this function:
template<Params> foo( Params const& p ) {
Here you either use MP if or regular if to switch to appropriate implementation. I find regular if *much* more convenient and easier to understand and implement
I would use the normal way of disabling function template overloads; SFINAE.
Ok. Here is an example: void foo_impl( int i1, int i2 ) {...} void foo_impl( int i1 ) {...} template<typename Params> void foo( Params const& p ) { if( p.has(i2) ) foo_impl( p[i1], p[i2] ); else foo_impl( p[i1] ); } Above is my solution to the resolving overloads based on presence of optional named function parameter. Could you type below how would yours look like?
int v = params.has(a) ? params[s] : 8; Then any other compile time interface you would invent.
I'm assuming you mistyped that, in which case it's spelled:
No, it's exactly like it supposed to be
int v = params[a | 8];
With our library.
And now compare: what is more obvious and easier to grasp?
3. Separation if implementation and invocation. The fact that you want to detect access to missing parameter at compile time assumes that during compiling if function invocation you have an access to function implementation.
No of course it doesn't assume that. The keyword parameters is part of the function *interface*, not the implementation.
The complete list of them - yes. But which one of them are optional, required or conditionally required is completely in function implementation domain.
IMO this is bad assumption in general and may not be the case in a future (with different implementation if templates). Don't take me wrong there some things we do want to check at compile time. But here we talking abut function implementation details, which caller do not need to know.
No, we are talking about the function interface, which the caller most likely should know about.
How are you supposed to now from 'select' function interface that timeout parameter is required iff mode parameter is WAIT? Accordingly in a point of select function invocation: select(( more =WAIT,priority=2,prefer_output=true)); You have no way to know that timeout is missing, while in following call select(( more =POOL,priority=0)); is not.
I'm done in this thread now.
.. I couldn't restrain myself.
I like this practice: during review just ignore all negative reviewers, hopefully people would missed it. Sorry, couldn't restrain myself.
-- Daniel Wallin
Gennadiy

Sorry. Don't know how this happened. It's repetition of other of my reply in other subthread. Gennadiy

You can't implement the same compile-time logic with less keystrokes. It's less capable because our design has a capability that yours doesn't. Not a matter of opinion, just a fact.
The only fact here is that you are making that statement. Let's take you "more-capable" interface and implement solution for simple problem. Let
take my interface and implement the solution for the same problem using my "less-capable" interface. Let than compare which variant is easier and shorter. And that would be *the fact* (it's still matter of taste/preference, but I hope we will be able to see it clearly). Until
Gennadiy Rozental wrote: then that
time you statement:
"You can't implement the same compile-time logic with less keystrokes"
*is* a matter of opinion and not a fact.
Fair enough. So, please show us your code
I already did presented my solution to the problem I think Dave had in mind. Authors on the other hand for some reason have difficulties backing up their statements with any examples, even pseudocode.
that "implement the same logic as with even less keystrokes"
I *never* told that my solution will use less keystrokes. Maybe less maybe more. That is not the point.
But please remember: less keystrokes doesn't mean better code.
Exactly my point. Ok. Here is how I understand the problem and how would solutions look like (be aware of my not that perfect understanding of submitted library): 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]); } 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).
Regards, -- Joel de Guzman
Gennadiy

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. 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. 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. 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. Doug

"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

On Nov 23, 2004, at 9:37 AM, Gennadiy Rozental wrote:
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message 1. It really trivial to implement the restriction on public level:
Ok.
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.
Precisely why I wrote "in some other scope", which refers both to different namespaces and different translation units :)
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.
Why is a listbox so important that it gets the short name "size" whereas the jeans get the longer name "cloth_size"? The example is good, but I don't think it strengthens your position at all. On the contrary, we see that "size" means very different things when talking about listboxes vs. when talking about jeans, but the word is not ambiguous in the context of each line.
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.
The BGL is _an_ example, but clearly not the only one. However, it does have the advantage of having had a named parameters mechanism for the last several years, so in my mind it carries significant weight relative to hypothetical usage scenarios.
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?
You are asking the wrong question. The right question is "which syntax is better for users?" Step back from the implementation, the language, and the limitations of both and determine what syntax you would like to use when calling these functions. Implementation details are secondary to interface details. Doug

"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message news:0BBD3222-3D6E-11D9-9E8D-000A95B0EC64@cs.indiana.edu...
On Nov 23, 2004, at 9:37 AM, Gennadiy Rozental wrote:
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message 1. It really trivial to implement the restriction on public level:
Ok.
Does this mean that you agree that submitted library does not provide "more-capable" interface?
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.
Precisely why I wrote "in some other scope", which refers both to different namespaces and different translation units :)
My point is why should I reuse? No, even you shouldn't without real reason..
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.
Why is a listbox so important that it gets the short name "size" whereas the jeans get the longer name "cloth_size"? The example is good, but I don't think it strengthens your position at all. On the contrary, we see that "size" means very different things when talking about listboxes vs. when talking about jeans, but the word is not ambiguous in the context of each line.
I believe my position in regards to parameter type is very simple. In legacy C++ we write: void foo( char const* name, int size ); void goo( char const* name, int size ); Function parameter entity has 3 unique "properties": 1. scope. defined by function name 2. name. Well, the name. 3. type. C++ enforce strict type checking. I believe "named parameters" solution should have the similar characteristics. Even though above function both have the same type and name it still two essentially different things. If we convert above functions to named parameter interface we should introduce scopes f and g (this is an extreme, but keep reading) and calls would look like: foo( foo::name = "abc" ); goo( goo::size = 5 ); Now in practice foo and goo probably belong to some namespaces aaa and bbb. Accordingly keywords may belong to respective namespaces and calls would look like: aaa::foo( aaa::name = "abc" ); or if we have using namespace bbb; goo( size = 5 ); The only exclusions where we may share the keywords are cases with series of related function. For example different constructors for the same class or different access methods within same class e.t.c. If we have keyword as a standalone entity, separated from function, this will bring following issues: 1. Where this keyword is defined? So that it could be reused by anybody who need 'size' parameter? 2. If we both defined keyword 'size' and both are reusable which one should Joe programmer should use? 3. Each function that uses this keyword need to repeat type checking. 4. Function may have two different size parameters, where should I use global size keyword and should I introduce my own for second one? All of that is escalated by what submitted solution propose in regards to type enforcing: struct f_keywords : keywords< named_param< name_t , boost::mpl::false_ , boost::is_convertible<boost::mpl::_, std::string> This interface is way too verbose IMO for the basic, but most widely needed, type enforcing feature.
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.
The BGL is _an_ example, but clearly not the only one. However, it does have the advantage of having had a named parameters mechanism for the last several years, so in my mind it carries significant weight relative to hypothetical usage scenarios.
The BGL is an example that uses typeless keywords (obviously because it's highly templated library). In my experience I had numerous other examples that used typed keywords. My position that for regular (non-template function) one would prefer typed keyword.
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?
You are asking the wrong question. The right question is "which syntax is better for users?" Step back from the implementation, the language, and the limitations of both and determine what syntax you would like to use when calling these functions. Implementation details are secondary to interface details.
This maybe the case would we were discussing named parameter feature for inclusion into language support. As it stands now, until we have template functions with variable length parameters list, the only viable option (IOW best for the user) IMO is single function interface. In theory I still would prefer single function interface: template<typename T[]> void foo( T[] const& params ) { std::cout << params[name] << params[value]; }
Doug
Gennadiy

On Nov 23, 2004, at 1:00 PM, Gennadiy Rozental wrote:
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message news:0BBD3222-3D6E-11D9-9E8D-000A95B0EC64@cs.indiana.edu...
On Nov 23, 2004, at 9:37 AM, Gennadiy Rozental wrote:
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message 1. It really trivial to implement the restriction on public level:
Ok.
Does this mean that you agree that submitted library does not provide "more-capable" interface?
I do not agree and it is not relevant. If you want to talk interfaces, then talk interfaces: alternative implementations of a library are not to be the focus of a review.
The only exclusions where we may share the keywords are cases with series of related function. For example different constructors for the same class or different access methods within same class e.t.c.
All of that is escalated by what submitted solution propose in regards to type enforcing:
struct f_keywords : keywords< named_param< name_t , boost::mpl::false_ , boost::is_convertible<boost::mpl::_, std::string>
This interface is way too verbose IMO for the basic, but most widely needed, type enforcing feature.
So use a typedef or create a metafunction. The important part of a general mechanism is that it can be used for many specific cases. If you want an additional interface for a typed keyword (or other such shortcuts), ask for it.
You are asking the wrong question. The right question is "which syntax is better for users?" Step back from the implementation, the language, and the limitations of both and determine what syntax you would like to use when calling these functions. Implementation details are secondary to interface details.
This maybe the case would we were discussing named parameter feature for inclusion into language support. As it stands now, until we have template functions with variable length parameters list, the only viable option (IOW best for the user) IMO is single function interface. In theory I still would prefer single function interface:
template<typename T[]> void foo( T[] const& params ) { std::cout << params[name] << params[value]; }
Everyone would prefer a single function interface. The library authors even provide a macro that makes the implementation look like it is providing a single function interface even when it can not be implemented as such. Doug

Gennadiy Rozental wrote:
Furthermore, you have O(N) instantiations for every lookup, we have O(1).
I do not understand your code that well to contradict you, but I frankly very much doubt so.
Actually you seem to have an mpl::find_if<> instantiation for every one of those, so make that O(N^2).
I use mpl algorithm to speed up delepoment. I may've use my own list implementation, as you do. And I don't expect it to see signifant diffence in both complexity and performance.
How can you be so sure? -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On Nov 17, 2004, at 9:46 PM, Gennadiy Rozental wrote:
Why would I ever want to invent global shared name keyword and used it anytime I want parameter name amoung my function parameters??
Because families of functions often take similar parameters. Consider how many algorithms in the Graph library accept a "weight_map" parameter: I counted at least 8 of them. How should we handle these weight map parameters for all of these functions, if we don't share the keyword? Doug

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
using the library primitives inside the "apply" function. After all, why not make "apply" a free function?
template <class Params> void apply(Params& p, Whatever x) { // use p's "passive" interface to operate on x }
This looks like good idea, but as it is you couldn't put it into library, since you don't know which interface to use to operate on x.
That's been my point all along. No matter how you arrange things, the apply function can't go in the library. AFAICT, our submission gives you all the tools a library could give to make writing such a function possible. What more could you want?
What you could do is to make above function to apply all params to x
template <class Params> void apply(Params& p, Whatever x) { for_each<Param>( do_apply_to(x) ); }
and user will be required to write do_apply functions:
void do_apply( name_param, A& a ) { a.m_name = name_param.value; }
void do_apply( suffix_param, A& a ) { a.m_name.append( name_param.value ); }
void do_apply( prefix_param, A& a ) { a.m_name.prepend( name_param.value ); }
You really want to write three overloads rather than a single apply function? It doesn't seem like a win to me.
Hmm. Well, I did not find it nor in docs. Why IMO it's most important part of functionality. I see it now in test. Why did you name function f_list? Why not just f as rest of them?
Where are you seeing f_list?
In your test program.
I honestly don't know why, but my guess is that it's named that way to distinguish that it expects a named parameter bundle instead of individual parameters.
I meant "within brackets". My problem is that it's p[name | "abc"] while I would prefer something like p[name] | "abc".
That's not doable in general. Suppose the argument was an int? What is
p[index] | 3
??
Yeah,. I understand.it's not possible. But within brackets is not very good either IMO
Opinion noted.
It could. I did that.
Please show how the library can help with the "active" part. The passive library can be used to build an active component easily enough. I just don't see how the library can help with the apply call.
Yes. User will be required to implement all apply calls for all parameters. Note though:
1. "Passive" solution does require the same: one need to 'apply' (assign) named parameter value to the target at the point of usage (not in the library)
What is this obsession with OO? You are assuming that there's a target. In the general case, you're wrapping functions.
2. In case of "active" solution you actually do it once and then could reuse it for many different functions
class Entry { };
class Logger { public: template<Params> log( msg, Params p ) { Entry e( msg ); p.apply_to( e );
e.flush(); }
template<Params> buffer( msg, Params p ) { m_entries.push_back( Entry( msg ) ); p.apply_to( m_entries.back() ); }
template<Params> buffer( multichunk_msg, Params p ) { m_entries.push_back( Entry( multichunk_msg ) ); p.apply_to( m_entries.back() ); }
vector<Entry> m_entries; };
As I've repeatedly said, I don't see any way that any library could help you to build an active solution more than our proposal does already.
Sorry. I still not sure I understand. Let me put it as following example:
template<typename T> void log( std::string prefix, std::string name, std::string separ, T const& v ) { std::cout << prefix << name << separ << v; }
template<typename Params> void log( Params const& p ) { log( p[prefix | "" ], p[name], p[separator | " = " ], p[value] ); }
Yeah. In this case keyword "value" couldn't be typed.
The light dawns?
Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use). I also eliminated "keyword coupling". Now it should be as good in this regard as submitted library.
It's still not as good because you don't provide for overload restriction via SFINAE.
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
Yeah. But in C++ de-facto standard approach for enforcing parameters types is to specify one.
Unless you're writing a function template.
If you have named template parameter it should be non-typed.
I guess you're not aware of the problems of overly-general function templates. Suppose you want to use a named parameter interface for this overload set? template <class T> void f(T*); template <class T> void f(boost::shared_ptr<T>&); Suppose you want to allow users to add new overloads, say for my_ptr<U>?
In other case it should be typed.
I do not know about python, but in c++ I prefer named interface wouldn't break by switching order of parameter specification.
What do you mean by "break?" When parameter names are used there is no restriction on parameter order.
f(arg1, arg2, arg3, key5 = arg5, key6 = arg6, key4 = arg4) ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positional position-independent.
Let consider an example of two optional parameters name, value. Then
foo( "abc", value = 5 ) works foo( value = 5 ) works foo( value = 5, "abc" ) doesn't work.
As it should be. Named parameters must always follow positional parameters. It's an easy rule to explain, and nobody gets confused.
These two are related; it should be clear from what I've written above. Your code can allow at most one of these (I didn't check): either it allows unchecked types and there's no ability to control overload resolution, or it doesn't support function templates with keyword arguments. And unless you have some way to induce SFINAE, you have no way to distinguish multiple overloads of the same function name accepting different named parameter sets:
int foo1( c_str name, float v, int i ) { }
int foo2( int id )
But you sad "multiple overloads of the same function" Above should look like int foo1( int id )
It doesn't matter one whit. I just used the names foo1 and foo2 for clarity. Change them both to food if you like!
{ }
template<class Params> int foo(Params const& params) { foo1( params[name], params[value], params[index] ); }
template<class Params> int foo(Params const& params) // error, foo already defined. { foo2( params[id] ); }
We don't need two. I would write:
template<class Params> int foo(Params const& params) { if( name and value present ) foo1( params[name], params[value], params[index] ); else foo1( params[index] ); }
No you can't. The two branches may not compile in the same instantiation. If no value was supplied and there's no default, accessing params[value] should be a compiler error. Plus, now you have an intrusive solution. A major reason to use overloading is that you *don't* have to modify an existing function to add an overload.
Yes. You can't develop keywords independently.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
A unique name is much easier to come up with than a unique number. With numbers all the keywords need to coordinate.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
Do we still care? Enough to affect the design/implementation?
Somebody cares.
I wouldn't be using it. Why would I use canon to kill sparrow.
Why would anyone kill a sparrow?!! ;-)
It's just Russian saying I was trying to translate.
I was only kidding. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

using the library primitives inside the "apply" function. After all, why not make "apply" a free function?
template <class Params> void apply(Params& p, Whatever x) { // use p's "passive" interface to operate on x }
This looks like good idea, but as it is you couldn't put it into library, since you don't know which interface to use to operate on x.
That's been my point all along. No matter how you arrange things, the apply function can't go in the library. AFAICT, our submission gives you all the tools a library could give to make writing such a function possible. What more could you want?
What you could do is to make above function to apply all params to x
template <class Params> void apply(Params& p, Whatever x) { for_each<Param>( do_apply_to(x) ); }
and user will be required to write do_apply functions:
void do_apply( name_param, A& a ) { a.m_name = name_param.value; }
void do_apply( suffix_param, A& a ) { a.m_name.append( name_param.value ); }
void do_apply( prefix_param, A& a ) { a.m_name.prepend( name_param.value ); }
You really want to write three overloads rather than a single apply function? It doesn't seem like a win to me.
It could. I did that.
Please show how the library can help with the "active" part. The passive library can be used to build an active component easily enough. I just don't see how the library can help with the apply call.
Yes. User will be required to implement all apply calls for all
1. What if both prefix and suffix above are optional. How would you implement above apply 2. What if I do not know about all possible grist to the name? What if I want to allow users to be able to extend set of possible "grists". In my proposition one could define own keyword and implement do_apply and that's it. parameters.
Note though:
1. "Passive" solution does require the same: one need to 'apply' (assign) named parameter value to the target at the point of usage (not in the library)
What is this obsession with OO? You are assuming that there's a target. In the general case, you're wrapping functions.
It's not an obsession. As I mention in my original post, in my experience I found most need in named parameter interface in constructors for some complex classes. There you have 'natural' target: this In case of functions passive solutions does look more attractive. Though in some cases (like one I disrobed above) I would still employ passive one.
2. In case of "active" solution you actually do it once and then could reuse it for many different functions
As I've repeatedly said, I don't see any way that any library could help you to build an active solution more than our proposal does already.
Traversing apply would help.
Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use). I also eliminated "keyword coupling". Now it should be as good in this regard as submitted library.
It's still not as good because you don't provide for overload restriction via SFINAE.
If you have named template parameter it should be non-typed.
I guess you're not aware of the problems of overly-general function templates. Suppose you want to use a named parameter interface for this overload set?
template <class T> void f(T*);
template <class T> void f(boost::shared_ptr<T>&);
Suppose you want to allow users to add new overloads, say for my_ptr<U>?
Following example works with my code: //////////////////////////////////////////////////////////////// // Example: #include <iostream> #include <boost/shared_ptr.hpp> namespace test { keyword<struct instance_t> instance; template<typename T> void foo_impl( T* t ) { std::cout << "non shared " << *t << std::endl; } template<typename T> void foo_impl( boost::shared_ptr<T> t ) { std::cout << "shared " << *t << std::endl; } template<class Params> void foo(Params const& params) { foo_impl( params[instance] ); } } int main() { using test::foo; using test::instance; int i = 5; foo( instance = &i ); foo( instance = boost::shared_ptr<float>( new float(1.2) ) ); return 0; }
Let consider an example of two optional parameters name, value. Then
foo( "abc", value = 5 ) works foo( value = 5 ) works foo( value = 5, "abc" ) doesn't work.
As it should be. Named parameters must always follow positional parameters. It's an easy rule to explain, and nobody gets confused.
Does it gets explained anywhere in docs?
template<class Params> int foo(Params const& params) { food( params[name], params[value], params[index] ); }
template<class Params> int foo(Params const& params) // error, foo already defined. { food( params[id] ); }
We don't need two. I would write:
template<class Params> int foo(Params const& params) { if( name and value present ) foo1( params[name], params[value], params[index] ); else foo1( params[index] ); }
No you can't. The two branches may not compile in the same instantiation. If no value was supplied and there's no default, accessing params[value] should be a compiler error.
It was pseudocode. It's a compile time if: if_<cond,invoke1,invoke2>::type::invoke( params );
Plus, now you have an intrusive solution. A major reason to use overloading is that you *don't* have to modify an existing function to add an overload.
Could you show in more details example for this case (including how you library solve the problem), then I could better comment it.
Yes. You can't develop keywords independently.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
A unique name is much easier to come up with than a unique number. With numbers all the keywords need to coordinate.
You also need to coordinate by combining all keyword designators into keywords structure. Though I agree that types are better (not significantly, would it cost to use types instead of numbers I would prefer numbers)
Dave Abrahams
Gennadiy.
participants (9)
-
Aaron W. LaFramboise
-
Daniel Wallin
-
David Abrahams
-
Doug Gregor
-
Gennadiy Rozental
-
Joel
-
Joel de Guzman
-
Rich Johnson
-
Thorsten Ottosen