Named parameters

B

Bill Pursell

I really like having the ability to specify parameter names
when I call a function, and I've been tempted to do things
like the following:

foo ( (struct foo_args){.area = 5, .base=4});

but it's clunky and forbidden by ISO c90 (according
to gcc with -pedantic).

However, I'm curious to hear people's thoughts on the
following style:


int foo(int area, int base, int height)
{
return area;
}

int main(void)
{
int area, base, height;
return foo(area = 5, base = 3, height = 10);
}

I'm a little nervous, because someone familiar
with a language where you actually can specify
parameters with this type of syntax might think they
can swap the parameter order, but I think it adds
clarity. Also, I'm intending that the variables be
unused, but I could anticipate code changes making use of
them, and that might obscure things somewhat. If
you were maintaining code like this, would you
like it, or dislike it?
 
B

Ben Pfaff

Bill Pursell said:
However, I'm curious to hear people's thoughts on the
following style:


int foo(int area, int base, int height)
{
return area;
}

int main(void)
{
int area, base, height;
return foo(area = 5, base = 3, height = 10);
}

I find this horrifying. If you're thinking about do that, why
not just make them comments:

return foo(/* area */ 5, /* base */ 3, /* height */ 10);

Another option, which is likely to be ridiculously inefficient on
compilers without a smart optimizer (not well proofread):

struct foo {
int area;
int base;
int height;
};

struct foo mk_foo(void) { struct foo f = {0, 0, 0}; return f; }
struct foo area(int area, struct foo f) { f.area = area; return f; }
struct foo base(int base, struct foo f) { f.base = base; return f; }
struct foo height(int height, struct foo f) { f.height = height; return f; }

...
return foo(area(5, base(3, height(10, mk_foo())));
 
W

William Ahern

I really like having the ability to specify parameter names when I call a
function
<snip>

Unfortunately, if you carry baggage like that around you'll pull your hair
out programming in C ;)
and I've been tempted to do things like the following:

foo ( (struct foo_args){.area = 5, .base=4});

but it's clunky and forbidden by ISO c90 (according to gcc with
-pedantic).

However, I'm curious to hear people's thoughts on the following style:
int area, base, height;
return foo(area = 5, base = 3, height = 10);
<snip>

Nothing wrong w/ using descriptive variable names, even if their only used
to pass a value to a function. But I think you already realize that such
stylistic games are non-conventional, and probably a poor idea in most
cases.

You'll grow weary swimming against the current.
 
E

Eric Sosman

Bill Pursell wrote On 06/21/06 13:52,:
I really like having the ability to specify parameter names
when I call a function, and I've been tempted to do things
like the following:

foo ( (struct foo_args){.area = 5, .base=4});

but it's clunky and forbidden by ISO c90 (according
to gcc with -pedantic).

However, I'm curious to hear people's thoughts on the
following style:


int foo(int area, int base, int height)
{
return area;
}

int main(void)
{
int area, base, height;
return foo(area = 5, base = 3, height = 10);
}

I'm a little nervous, because someone familiar
with a language where you actually can specify
parameters with this type of syntax might think they
can swap the parameter order, but I think it adds
clarity. Also, I'm intending that the variables be
unused, but I could anticipate code changes making use of
them, and that might obscure things somewhat. If
you were maintaining code like this, would you
like it, or dislike it?

I would dislike it intensely, so intensely that I would
probably "maintain" such code by discarding and rewriting
it from scratch.

Principal objection: It's guilty of false advertising
(this is the first of the two problems you yourself cite).
Like a used car salesman, you lure the unwary sucker onto
the lot with promises you do not intend to keep and could
not keep even if you wanted to. (You know the difference
between a used car salesman and a programmer, I hope? The
salesman understands that he's lying.) I would avoid this
technique for the same reason I would not use heapSort()
as the name of a function that prompts the user to make a
choice from a menu.

Second objection: It's obfuscated. Reading the code,
I'd immediately wonder why you needed the side-effects of
setting those three variables, and I'd go hunting around
trying to understand your purpose. "Write-only" variables
are clearly not being used in the C as such; is it possible
that you're saving the as-of-the-call argument values for
the benefit of an unnamed debugger or something? I'd spend
a whole lot of time trying to understand your purpose when in
fact you don't have one, and by the time I figured out that
the assignments were purposeless I'd have lost the thread of
whatever it was that caused me to read the code in the first
place. (By the way: At least some lint versions will issue
warnings for storing values that are then never used.)

Third (weakest) objection: Efficiency. I'm not terribly
worried about this, because a few extra assignments won't make
an enormous difference -- maybe a factor of three or four in
the cost of the function call, but not a hundredfold increase.
Still, things could add up if you had a lot of arguments (when
documenting their nature would be of greatest importance) or
if some of them were great big beefy structs being passed by
value. I'm no fan of trying to squeeze the last milliquiver
out of the code, but even as a former cycle-shaver who's gone
on the wagon for lo! these many years I still find it galling
to spend cycles on the purchase of zero computational progress.

Your initial trick, with the arguments all in a struct,
at first looks attractive. It's also supported by the newest
"C99" version of the Standard (although I'd need to double-
check the syntax), so you might not need to be tied to gcc if
you were to use it. But on second thought, I think the trick
is a bad idea because it emasculates the function prototypes.
Yes, the prototype would force you to pass a struct foo_args
and not an int or a pointer or some other kind of struct, but
the prototype is not able to insist that all the struct members
be given values. The compiler will complain if you omit an
argument in

void foo(int, int);
foo(42, 56);
foo(99); /* Objection, Your Honor! */

.... but will be perfectly content with

struct foo_args { int area, base; };
void foo(struct foo_args);
foo( (struct foo_args){.area=42, .base=56} );
foo( (struct foo_args)(.area=99} ); /* Silence ... */

The trick sacrifices a safeguard, which seems to me a cure
worse than the disease.
 
M

Malcolm

Bill Pursell said:
int main(void)
{
int area, base, height;
return foo(area = 5, base = 3, height = 10);
}

I'm a little nervous, because someone familiar
with a language where you actually can specify
parameters with this type of syntax might think they
can swap the parameter order, but I think it adds
clarity.
That's the problem. Some lanugages, like the R programming environment, do
allow parameters to be specified by name when called. C doesn't, and
prentending that it does causes confusion.
Also, I'm intending that the variables be
unused, but I could anticipate code changes making use of
them, and that might obscure things somewhat. If
you were maintaining code like this, would you
like it, or dislike it?
You really have to stick to the convention. The issue of whether R calling
format is better or C is better is irrelevant. When you are writing C, do
things in the C way.
 
C

Clever Monkey

Malcolm said:
That's the problem. Some lanugages, like the R programming environment, do
allow parameters to be specified by name when called. C doesn't, and
prentending that it does causes confusion.
You really have to stick to the convention. The issue of whether R calling
format is better or C is better is irrelevant. When you are writing C, do
things in the C way.

Some of the best advice I was given early on was "when doing Java, think
like a Java coder; when in C, think like a C coder". This not only
applies (where I am) to syntax, but also how one names variables and
splits work up into modules.
 
M

Martin Ambuhl

Bill said:
I really like having the ability to specify parameter names
when I call a function, and I've been tempted to do things
like the following:

foo ( (struct foo_args){.area = 5, .base=4});

but it's clunky and forbidden by ISO c90 (according
to gcc with -pedantic).

That sort of initializer doesn't exist in C90 even in declarations. If
you insist on using C99 features, don't tell the compiler you are using
c90. Try this, but with the compiler set for c99 (or gnu99):

#include <stdio.h>

struct foo_args
{
int area, base, height;
};


int foo(struct foo_args x)
{
return x.area;
}

int main(void)
{
printf("%d\n", foo((struct foo_args) {
.area = 5,.base = 3,.height = 10}));
return 0;
}

However, I'm curious to hear people's thoughts on the
following style:


int foo(int area, int base, int height)
{
return area;
}

int main(void)
{
int area, base, height;
return foo(area = 5, base = 3, height = 10);
This return statement, even if the syntax were right, is not
portable unless the return value from foo is one of 0, EXIT_SUCCESS, or
EXIT_FAILURE said:
}

I'm a little nervous, because someone familiar
with a language where you actually can specify
parameters with this type of syntax might think they
can swap the parameter order, but I think it adds
clarity.

I'm not convinced. Namelist-looking arguments _do_ imply that the order
is irrelevant and encourages errors. Provide and use decent
documentation. The users of this function will still need to know the
right order. If you insist on "meaningful" argument lists, then
area = 5;
base = 3;
height = 10;
foo(area, base, height);
will do.
Also, I'm intending that the variables be
unused, but I could anticipate code changes making use of
them, and that might obscure things somewhat. If
you were maintaining code like this, would you
like it, or dislike it?

I would think it written by a beginner who had no idea what language he
was using.
 
F

Frederick Gotham

Clever Monkey posted:

Some of the best advice I was given early on was "when doing Java,
think like a Java coder; when in C, think like a C coder". This not
only applies (where I am) to syntax, but also how one names variables
and splits work up into modules.


I have great disdain for advice such as that.

I prefer to use my own head, make my own decisions. For instance:
No matter how many times I see a master programmer use "i++", I'm
still going to use "++i". No matter how much I see people use macros in
C, I'm always going to use a viable substitute where possible (e.g.
"enum" or "typedef").

In all walks of life, I detest the kind of people who blindly follow
doctrine, rather than "do things their own way", using their own
intelligence.

One good example is this:
On a C++ newsgroup once upon a time, someone posted regarding using
unsigned integers to loop backwards to zero; obviously the following
doesn't work:

for(unsigned i = 88; i >= 0; ++i);


Then... when someone suggested using:

for(unsigned i = 88; i != -1; ++i);


, the group were overwhelmingly against it, saying it was cryptic, and
that it wouldn't survive a "code review". On a C newsgroup however, I
think you'd find that far more people would find it acceptable (the
majority perhaps), because C programmers tend to have more cop-on when it
comes to the core functionality of the language. Anyway, the moral of the
story is that I wouldn't hesitate for a second to do things my own way,
even when writing a C++ program. 95% of the C++ community may scorn me
for using arrays of char's rather than std::string, but I just don't
care. In fact, I challenge them to write code as efficient as mine.
 
F

Frederick Gotham

Frederick Gotham posted:

obviously the following
doesn't work:

for(unsigned i = 88; i >= 0; ++i);


Then... when someone suggested using:

for(unsigned i = 88; i != -1; ++i);


Should have written:

--i


rather than "++i" in both loops.
 
J

jaysome

Clever Monkey posted:




I have great disdain for advice such as that.

I prefer to use my own head, make my own decisions. For instance:
No matter how many times I see a master programmer use "i++", I'm
still going to use "++i". No matter how much I see people use macros in
C, I'm always going to use a viable substitute where possible (e.g.
"enum" or "typedef").

In all walks of life, I detest the kind of people who blindly follow
doctrine, rather than "do things their own way", using their own
intelligence.

One good example is this:
On a C++ newsgroup once upon a time, someone posted regarding using
unsigned integers to loop backwards to zero; obviously the following
doesn't work:

for(unsigned i = 88; i >= 0; ++i);


Then... when someone suggested using:

for(unsigned i = 88; i != -1; ++i);


, the group were overwhelmingly against it, saying it was cryptic, and
that it wouldn't survive a "code review". On a C newsgroup however, I
think you'd find that far more people would find it acceptable (the
majority perhaps), because C programmers tend to have more cop-on when it
comes to the core functionality of the language.

That is cryptic and unnecessary. PC-lint warns:

Warning 650: Constant '-1' out of range for operator '!='

I see that warning and immediately I get chills up my spine and I get
two thoughts in my mind: either I spend the time looking up PC-lint
message definitions and consulting the C standard; or I intuitively
fix the obvious "warning". I, as a C programmer (or C++ programmer for
that matter), would choose the latter, and furthermore, it would teach
me a good lesson not to do it again.
 
F

Frederick Gotham

jaysome posted:

Warning 650: Constant '-1' out of range for operator '!='


If I was writing C++ code, I'd have the choice of:


numeric_limits< Type >::max()


But nonetheless I'd still use -1.


As for the warning sending chills up your spine, you can always cast it
away:

i != (unsigned)-1;

or, in C++:

i != implicit_cast<unsigned>( -1 );
 
R

Richard Heathfield

Frederick Gotham said:
Clever Monkey posted:




I have great disdain for advice such as that.

I prefer to use my own head, make my own decisions. For instance:
No matter how many times I see a master programmer use "i++", I'm
still going to use "++i". No matter how much I see people use macros in
C, I'm always going to use a viable substitute where possible (e.g.
"enum" or "typedef").

In all walks of life, I detest the kind of people who blindly follow
doctrine, rather than "do things their own way", using their own
intelligence.

One good example is this:
On a C++ newsgroup once upon a time, someone posted regarding using
unsigned integers to loop backwards to zero; obviously the following
doesn't work:

for(unsigned i = 88; i >= 0; ++i);

Sure (and yes, I know you meant --i). And presumably you want values 88 to
0, inclusive at both ends...
Then... when someone suggested using:

for(unsigned i = 88; i != -1; ++i);

....someone else suggested:

i = 89;

while(i-- > 0)
{
...
}

....and the crowd went wild.
 
F

Frederick Gotham

Richard Heathfield posted:
...someone else suggested:

i = 89;

while(i-- > 0)
{
...
}

...and the crowd went wild.


Yes, that's another solution, although it doesn't use a "for" loop.
 
N

Nick Keighley

Frederick said:
jaysome posted:

[testing an unsigned against -1]
If I was writing C++ code, I'd have the choice of:

numeric_limits< Type >::max()

But nonetheless I'd still use -1.

As for the warning sending chills up your spine, you can always cast it
away:

i != (unsigned)-1;

or, in C++:

i != implicit_cast<unsigned>( -1 );

is this a new type of cast?


--
Nick Keighley

"Using a 64-bit value introduces a new wrap around date in about 290
billion
years, on Sunday, December 4, 292,277,026,596 15:30:08 UTC. This
problem is
not, however, widely regarded as a pressing issue."
wiki/Year_2038_problem
 
R

Richard Heathfield

Frederick Gotham said:
Richard Heathfield posted:



Yes, that's another solution, although it doesn't use a "for" loop.

This one does:

for(i = 89; i-- > 0; )
{
...
}
 
V

Victor Bazarov

Nick said:
Frederick said:
jaysome posted:

[testing an unsigned against -1]
If I was writing C++ code, I'd have the choice of:

numeric_limits< Type >::max()

But nonetheless I'd still use -1.

As for the warning sending chills up your spine, you can always cast
it away:

i != (unsigned)-1;

or, in C++:

i != implicit_cast<unsigned>( -1 );

is this a new type of cast?

I think it exists in Boost.

Also, it's something that was recently under discussion in comp.std.c++.
Check out the thread "Defect: Missing fundamental feature!"

http://groups.google.com/group/comp.std.c++/browse_frm/thread/8b7617618a67f610/

V
 
C

CBFalconer

Richard said:
Frederick Gotham said:
.... snip ...

Sure (and yes, I know you meant --i). And presumably you want
values 88 to 0, inclusive at both ends...


...someone else suggested:

i = 89;

while(i-- > 0)
{
...
}

...and the crowd went wild.

They went totally ape over:

i = UPPERLIMIT;
do {
...
} while (LOWERLIMIT < i--);
 
F

Frederick Gotham

Nick Keighley posted:

is this a new type of cast?


Yes, I realise we're off-topic here, but the three new-style casts are:

static_cast
reinterpret_cast
const_cast


Many people, (myself included), have wanted a fourth one, "implicit_cast".
Until it gets officially added to the language, we can achieve its
functionality using a template provided by Boost.
 
P

Phlip

[followups set to C++]

Many people, (myself included), have wanted a fourth one, "implicit_cast".
Until it gets officially added to the language, we can achieve its
functionality using a template provided by Boost.

Why should it be a keyword? Or do you just mean someone should move the
template from Boost to the Standard? What would a keyword do that the
template couldn't?

I like languages that permit us to build as many of its keyword-level things
from primitives as possible...
 
M

Marcus Kwok

In comp.lang.c++ Frederick Gotham said:
Nick Keighley posted:

Yes, I realise we're off-topic here, but the three new-style casts are:

static_cast
reinterpret_cast
const_cast

You forgot dynamic_cast.

Followups set to clc++ only.
 

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

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top