Re: Variables in for loop (style issue)
Maciej Sobczak wrote:
James Kanze wrote:
What is obviously being refered to is programmer efficiency.
Not that of the person writing the code, since this is
obviously the most efficient solution for him, but of the
person reading it.
Exactly, this is the source of the discussion. Or, putting it
another way, how many precise things can we say about the code
by just reading it without resorting to larger-scale code
analysis.
I keep referring back to what my high school English teacher
said: "Good writing is clear and concise." The more you say
with the less words, the more the code is concise. At some
point, however, the cost in clarity outweighs the additional
conciseness. Up until there, I think most of us would agree.
Trying to find a concensus as to where that last point is,
however, is going to be difficult.
There are two things that provoked me to post my questions.
First is that there are really coding standards that force
programmers making the kind of distinctions I've tried to
describe.
Nothing new there. It's not rare that there is no really good
solution, and you have to choose the least bad.
Second is that there are languages which actually make such
distinctions more natural than C++. Some say that those
languages are more appropriate for safety-critical domains,
exactly becauese they don't blur the distinctions that may
prove important.
Maciej's contention is that this loop misleads the reader
into thinking that something in the loop does modify the
size of the array. I don't agree with him; I use v.size()
(or v.end(), or whatever) a lot even when the vector's size
won't be modified, as do most of the people I've worked
with, so we don't read this into the call to v.size().
Which is a very good argument. My experience with other
programmers is exactly the same - writing v.size() in the
second caluse of the for loop is a common and well understood
idiom. The ojective is, however, to build a better
understanding of *why* things are done the way they're done,
even when it comes to things like for loops (kind of Andrei's
"improving at all levels" idea - note also that respected
authors spent pages in CUJ discussing how basic stuff like for
loops should be written, so I'm in a good company ;-) ).
Well, CUJ had to have something to put into its articles:-).
Seriously: if you're actually writing code, Pete had the only
correct answer. Stopping to even think about it costs
productivity, and may result in delays in the delivery of the
product. But of course, you're not actually writing code when
you post an article in this forum, and some meta-discussion
concerning what should be in the programming guidelines is
always necessary, in any project.
My personal opinion is that you're taking things a little too
far; that it isn't that important, that the additional
information you want to impart isn't important enough (in the
general case, anyway) to add complexity to the written form of
the program. Nor to invest the time necessary to ensure that
all of the programmers on the project are aware of the
convention, and profit from it -- if most of the readers of your
code see the altnerances as random variations, rather than a
signal "size changes or not", then all you've done is add noise.
Taking this all into account, the question is how to write
code in the way that is self-descriptive to the extent that
cannot be possibly improved. And even when it comes to such
simple things I can see contradicting recommendations. Some
suggest calling v.size() every time, because it's more
defensive (always "works"). Others suggest to use for_each.
And it's already where we have contradiction, because for_each
is *not* defensive in the above sense - it evaluates the
loop's limiting conditions only once.
But for_each says that you don't modify the size... or do
anything else which might invalidate its iterators. That's part
of the message of using for_each -- the loop is executed exactly
n times, where n is determined before entering the loop. In
fact, that's its only message: that there are no break's, no
continue's and no other fiddling around which will change this.
I think that this is generally known and recognized by
programmers familiar with the STL. That is: the message will be
understood immediately, and I don't need any particular
"training" for the programmers for it to pass.
Anyway - if I have in my program two loops, one where the
limiting condition changes and one where it doesn't, I
consider that they express different designs and therefore I
want them to *look* differently.
I can understand that, although I'm not sure that everyone
considers it so important. There is a logical difference
between a loop which executes exactly n time, n being determined
once and for all before the start of the loop, and more general
loops. The questions are 1) how much does it cost (in
conciseness) to impart this information by means of the loop
structure, and 2) how much extra work, if any, is necessary to
ensure that the information will be understood.
Calling v.size() all the time blurs this distinction
Only if you suppose that the position of the call is distinctive
in this regard. I would generally expect the loop not to change
the size of the vector, regardless of where the call is. But it
occurs to me that I have at least a couple of exceptions --
cases where I switched from iterators to an index because I was
doing push_back's (and invalidating the iterators) in the loop.
So I don't know.
In the end, I think that the question only really becomes
relevant when you know why the loop is there -- what its role in
the algorithm is. And once you know that, you probably do know
whether the vector changes size or not, independantly of where
the call to v.size() is.
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]