Sugg: statically resolved parameter passing by name

H

hank lawson

When designing a function it is important to order the parameters in
order the expected probability that they must deviate from their
default values. However, when more parameters are needed, one
inevitably runs into cases where some parameters should be set with
non-default parameters while the preceeding parameters should still
use default values.

For example, consider the following function:

void func( int a, int b, int c = 0, int d = 1, int e = 2, int f = 3 )
{
....
}

The programmer may need to write:

func(a,b,0,1,2,0);

which can become inconvenient because it requires filling in all the
default values, which is cumbersome and increases the chances of
bugs.

A better and more flexible solution for passing parameters would be to
allow syntax such as the following:

func(a,b,f=0);

In this case, all parameters assume their default values except for
f. The notation is not ambiguous and is easy to understand. It is
also simple for the resolution to be evaluated statically so there is
no loss of runtime performance.

Moreover, it makes the code more flexible because the function can be
refactored by changing the order of unused parameters without breaking
the calling code.
 
Ö

Öö Tiib

When designing a function it is important to order the parameters in
order the expected probability that they must deviate from their
default values.  However, when more parameters are needed, one
inevitably runs into cases where some parameters should be set with
non-default parameters while the preceeding parameters should still
use default values.

For example, consider the following function:

void func( int a, int b, int c = 0, int d = 1, int e = 2, int f = 3 )
{
...

}

A function with more than 5 parameters is smelly. Usage of magic
numbers is smelly. Can you come up with some reasonable examples at
least? It is too hard to imagine myself writing something that is
named 'func'.
The programmer may need to write:

func(a,b,0,1,2,0);

It is hard to understand what for what so you should probably delete
both that function and its calling code anyway. How you pass review
with that?
which can become inconvenient because it requires filling in all the
default values, which is cumbersome and increases the chances of
bugs.

A better and more flexible solution for passing parameters would be to
allow syntax such as the following:

func(a,b,f=0);

In this case, all parameters assume their default values except for
f.  The notation is not ambiguous and is easy to understand.  It is
also simple for the resolution to be evaluated statically so there is
no loss of runtime performance.

Moreover, it makes the code more flexible because the function can be
refactored by changing the order of unused parameters without breaking
the calling code.

Boost.Parameter library is designed for it. It sort of works only that
declaring functions with named parameters is not too elegant. I am not
sure if such medicine is best cure for the disease.
 
J

Joshua Maurice

When designing a function it is important to order the parameters in
order the expected probability that they must deviate from their
default values.  However, when more parameters are needed, one
inevitably runs into cases where some parameters should be set with
non-default parameters while the preceeding parameters should still
use default values.

For example, consider the following function:

void func( int a, int b, int c = 0, int d = 1, int e = 2, int f = 3 )
{
...

}

The programmer may need to write:

func(a,b,0,1,2,0);

which can become inconvenient because it requires filling in all the
default values, which is cumbersome and increases the chances of
bugs.

A better and more flexible solution for passing parameters would be to
allow syntax such as the following:

func(a,b,f=0);

In this case, all parameters assume their default values except for
f.  The notation is not ambiguous and is easy to understand.  It is
also simple for the resolution to be evaluated statically so there is
no loss of runtime performance.

Moreover, it makes the code more flexible because the function can be
refactored by changing the order of unused parameters without breaking
the calling code.

C++ only has positional parameters. It does not have named parameters.
I doubt it will ever have named parameters. I suggest reading the C++
faq for a good workaround which gives you basically all of what you
want. Google: C++ faq named parameter idiom
 
A

Andrey Vul

C++ only has positional parameters. It does not have named parameters.
I doubt it will ever have named parameters. I suggest reading the C++
faq for a good workaround which gives you basically all of what you
want. Google: C++ faq named parameter idiom

Named parameter evaluation looks O(sum(k=1,n, (n c (n-k)) * (n p k))).
This is sure to slow down compile time since it looks like
O(sum(k=1,n, (n c (n-k)) * (n p k)) function signatures can be
created. Using named parameters or passing something like a
map<string, const void *> and static_cast<const arg_type *> would be
far more efficient if the named function idiom is unsuitable.

Also, named parameter idiom as described in c++ faq applies to where
you have T::T(A const& x, A const& y) and T::T(A const& x, A const&
z), not T::T(A const& x, B const& y) and T::T(B const& y, A const& x),
since in the first case the compiler sees both having the same
signature (A const&, A const&), as opposed to the second case which is
(A const&, B const&) , (B const&, A const&). Now, in this case, there
should be something like T::foo(A const&, B const&) and T::bar(B
const&, A const&). The only somewhat elegant solution is to use a
map<string, const void *> to varargs it. This is O(n*log(n)+n), which
is significantly less than O(sum(k=1,n, (n c (n-k)) * (n p k))). Plus,
you free the symbol table - debugging linker errors where you have n!
function signatures could be worse than debugging why stl code won't
compile.

You could also have a struct with all the arg types and deref their
pointers, with NULL/nullptr/0/SOME_RESERVED_VALUE being 'use default
value'. I'd go for the map, since it looks like less of a pain for the
maintainer and user, as helper classes aren't needed.
 
A

Andrey Vul

Named parameter evaluation looks O(sum(k=1,n, (n c (n-k)) * (n p k))).

The huge Big-O is because it is simply inefficient to do named varargs
at compile time. If I have to varargs a function, I just use a
map<string, const void *> and static_cast & dereference. For debugging
purposes, assert via exception that the expected type of the argument
matches its typeid (check for non-null first).
 
J

Joshua Maurice

The huge Big-O is because it is simply inefficient to do named varargs
at compile time. If I have to varargs a function, I just use a
map<string, const void *> and static_cast & dereference. For debugging
purposes, assert via exception that the expected type of the argument
matches its typeid (check for non-null first).

I don't think the common implementation will compile down the C++
Named Parameter Idiom like you think it will. varargs generally
involves parsing a format string. The C++ Named Parameter Idiom does
not. Ex:

int main()
{
SomeType foo = SomeType::builder().x(1).b(2).r(5).doit();
}

Is likely "equivalent" to:

int main()
{
SomeType::Builder builder;
builder.x = 1;
builder.b = 2;
builder.r = 5;
SomeType foo(builder);
}

Which is itself likely "equivalent" to:

int main()
{
SomeType foo(0, 2, 0, 0, 0, 0, 5, 0, 0, 0, 1);
}

A good optimizing compiler should make pretty efficient code for the C+
+ Named Parameter Idiom. It will not compile down to assembly like
common vararg usage ala printf - there is no runtime parsing of a
format string or equivalent.
 
J

Joshua Maurice

I don't think the common implementation will compile down the C++
Named Parameter Idiom like you think it will. varargs generally
involves parsing a format string. The C++ Named Parameter Idiom does
not. Ex:

  int main()
  {
    SomeType foo = SomeType::builder().x(1).b(2).r(5).doit();
  }

Is likely "equivalent" to:

  int main()
  {
    SomeType::Builder builder;
    builder.x = 1;
    builder.b = 2;
    builder.r = 5;
    SomeType foo(builder);
  }

Which is itself likely "equivalent" to:

  int main()
  {
    SomeType foo(0, 2, 0, 0, 0, 0, 5, 0, 0, 0, 1);
  }

A good optimizing compiler should make pretty efficient code for the C+
+ Named Parameter Idiom. It will not compile down to assembly like
common vararg usage ala printf - there is no runtime parsing of a
format string or equivalent.

Oh, we're talking about compile speeds? I'm sorry. I just re-read that
and I think that's what you're saying.

Yes. I expect that the Named Parameter Idiom takes longer to compile
than vararg usage ala printf. However, I can't imagine that it would
take that much longer though.

Also, you're talking about Big-O on input of what I'd guess is
typically less than 50. With such small input sizes with standard
polynomials, Big-O isn't the most useful. It's not "big enough". I'd
want to measure it instead. (Note that I still agree that vararg
compilation would probably be quicker.)

Finally, if you're using C++ then the emphasis is generally much more
on the runtime than the compile time. How often are you really
concerned about compile time differences of less than 1%?

PS: Yes, you would be very concerned with compile times of 2x or 10x,
but the Named Parameter Idiom would never cause that. For gains like
that, you almost certainly need to be looking at making your build
parallel or distributed, making your build incremental, or reducing
down the number of included headers such as with the pImpl Idiom.
 
R

Rolf Magnus

hank said:
A better and more flexible solution for passing parameters would be to
allow syntax such as the following:

func(a,b,f=0);

In this case, all parameters assume their default values except for
f. The notation is not ambiguous and is easy to understand.

It is ambiguous. That code already has a meaning in C++. Something roughly
like:

f = 0;
func(a,b,f);
 
J

Jeff Flinn

hank said:
When designing a function it is important to order the parameters in
order the expected probability that they must deviate from their
default values. However, when more parameters are needed, one
inevitably runs into cases where some parameters should be set with
non-default parameters while the preceeding parameters should still
use default values.

For example, consider the following function:

void func( int a, int b, int c = 0, int d = 1, int e = 2, int f = 3 )
{
...
}

The programmer may need to write:

func(a,b,0,1,2,0);

which can become inconvenient because it requires filling in all the
default values, which is cumbersome and increases the chances of
bugs.

A better and more flexible solution for passing parameters would be to
allow syntax such as the following:

func(a,b,f=0);

see boost parameter library se::
http://www.boost.org/doc/libs/1_45_0/libs/parameter/doc/html/index.html

Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top