
"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