Can you name some of those benefits? They're not clear to me.
Sure. In a previous post I listed some specific cases where it's
useful to have the initial value available (quoting):
showing the value with printf for some tracing
writing an assertion relating the function's output and input
viewing the value while debugging
All of these uses (not to mention some others) tend to show up
later in the development cycle as much as they do earlier when
the code is first written. It often isn't possible to
anticipate on first writing when the original value will
subsequently be needed.
[End of quoting.]
There's also a different kind of benefit having to do with
comprehensibility. For example, in long functions, it's
usually better to initialize a loop variable right before
the loop: because the initialization is right there, it's
easy to see what it is, and know that the variable hasn't
been inadvertently set to the wrong thing. We can't do
that with a parameter -- it had to be initialized at the
beginning. Compare
t = n*3 + 7;
...
while( t-- ){
...
}
with
for( t = n*3 + 7; t--; ){
...
}
The second is better (I claim), because everything we
have to read for the loop is right there at the loop.
We don't always have this choice if parameters are used
in loops, because of how they are initialized.
Another example of a comprehensibility benefit is where
on the spectrum of imperative vs functional a piece of
code is. The more there is state that changes, and the
less there is state that doesn't change, generally the
harder we have to work to understand a given piece of
code. For example, compare
size_t
length_of_string( const char *s ){
size_t n = 0;
while( *s ) s++, n++;
return n;
}
with
size_t
length_of_string( const char *s ){
size_t n = 0;
while( s[n] ) n++;
return n;
}
I admit the difference between these functions isn't very big,
and in a code review I'd probably be ok with either one. But
the second one is a little easier to understand. I can see at a
glance that 'n' holds the index of the first null character in
the string 's'. Of course, I can see that in the first function
also, but there's a little more mental effort involved. You
see what I mean?
Summarizing the two examples above: a benefit of keeping
parameters unchanged is that it allows or encourages other
good development practices.
(I agree that modifying function parameters is not something
you'd want to do every day, but sometimes it's convenient -- more
so that introducing a local variable to hold a modifiable copy --
and I don't understand the predilection in some circles for
mandating that parameters not be modified.)
I expect we're not really that far apart on this. Let me offer
an analogy. Usually it's better for (non-const) variables to be
initialized subsequent to their declaration. Not always better,
not hugely better, but usually better. Every so often I am
tempted to "break the rule" and write initializing declarations.
When I give in to that temptation, probably 999 times out of
1000 everything works out fine. But every now and then I get
bitten by it. That's the thing: when I break the rule,
sometimes I get bitten; but when I follow the rule, I never do.
I suspect people who are strong advocates of never modifying
parameters do so largely for that reason - if one follows the
rule, one never gets bitten.
So if you want to make exceptions now and then, that's ok, just
be sure you bring your venom kit with you.