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.