Why Not Local Loops? Reasons Explained

  • Thread starter Thread starter jk22
  • Start date Start date
  • Tags Tags
    Local Loops
Click For Summary

Discussion Overview

The discussion revolves around the practice of declaring loop control variables within the scope of a loop in programming, particularly in C and C++. Participants explore the implications of this practice, including coding standards, scope management, and the potential for confusion in variable naming.

Discussion Character

  • Debate/contested
  • Technical explanation
  • Conceptual clarification

Main Points Raised

  • Some participants argue that declaring loop variables within the loop is acceptable and can enhance code readability by limiting the variable's scope.
  • Others suggest that traditional practices recommend declaring variables at the top of a program to avoid scope-related issues, particularly in older C standards.
  • A few participants mention that coding standards, such as MISRA, advise against inline declarations to prevent variable shadowing and enhance code reviewability.
  • Some express that using generic variable names like 'i' or 'j' can lead to maintenance challenges, advocating for more descriptive names instead.
  • There is a discussion about the performance implications of variable scope and locality in relation to CPU cache behavior, particularly in the context of C99's allowance for inline declarations.
  • Participants note that while some instructors may discourage inline declarations, many programmers find them practical and commonly used in modern coding practices.

Areas of Agreement / Disagreement

Participants do not reach a consensus on the best practice regarding loop variable declarations. There are multiple competing views on the appropriateness of inline declarations versus traditional variable declarations, as well as differing opinions on naming conventions.

Contextual Notes

Some participants highlight the importance of context in coding standards, noting that different environments may have varying requirements. The discussion also reflects a tension between modern programming practices and older conventions.

Who May Find This Useful

Programmers, software developers, and students interested in coding standards, variable scope management, and best practices in loop construction may find this discussion relevant.

jk22
Messages
732
Reaction score
25
Once i did the following :

for (int i=0;i <100;i++) {...}

Hence with the i defined only in the loop and the professor told me we shall never do that.

Do you know any reason ?

Thanks.
 
Technology news on Phys.org
jk22 said:
Once i did the following :

for (int i=0;i <100;i++) {...}

Hence with the i defined only in the loop and the professor told me we shall never do that.

Do you know any reason ?
The only reason I can think of is that compilers prior to the C99 spec didn't allow intermingling of declarations and executable statements, as you have in the for loop above. Other than that, I can't think of any reason why the above wouldn't be fine.
 
I can't see anything really wrong with this.
It sets up a loop which you want to iterate 100 times, and there could be a perfectly good reason why you want to do that.
Possibly the tutor is objecting to the fact that no matter what goes on inside the loop, it's still always going to execute 100 times.
It's generally more useful to have a loop which will terminate depending on some condition occurring inside the loop.
 
jk22 said:
Once i did the following :

for (int i=0;i <100;i++) {...}

Hence with the i defined only in the loop and the professor told me we shall never do that.

Do you know any reason ?

Thanks.

Some instructors think that you should write a WHILE loop instead (and escape it on the appropriate condition), but really, people do the above all the time and I really don't have a problem with it. If you want to escape the loop before it goes 100 times, you can just use a break statement.
 
Yes often we want to iterate an indexed array and at some condition being found escape with an index set of where we exitted the loop.
 
The OP didn't say anything about exiting the loop early. If I know I'm going to want to exit early, I normally write it as a while loop, myself.

I took the question to be about declaring i as part of the loop initialization, which restricts its scope to inside the loop. I consider this to be a good thing, if you don't intend to use i outside the loop. It's like declaring local variables for a function instead of using global variables.

If you want to use a variable named i somewhere else in the program, you have to declare it again outside the loop, and this means you actually have two separate variables named i. Changing the value of i inside the loop doesn't change its value outside the loop, and vice versa.
 
  • Like
Likes   Reactions: DrClaude and jedishrfu
I tend to use a for loop when I have something that is indexed and a while loop when I don't rather than having a while that increments an index. It just depends on which is more elegant to me at the time I'm writing the code.
 
Yes, there is an aspect of programming as an art form, rather than 'engineering'.
However in most employment, the employer doesn't give a damn as long as it works.
 
  • Like
Likes   Reactions: jedishrfu
rootone said:
However in most employment, the employer doesn't give a damn as long as it works.

Someone will probably chime in about coding standards at many companies / organizations...
 
  • #10
jk22 said:
Once i did the following :

for (int i=0;i <100;i++) {...}

Hence with the i defined only in the loop and the professor told me we shall never do that.

Do you know any reason ?

Thanks.
I think the take-home lesson here is that there are different programming standards in different circumstances. Often, if you are working in a team, there will be standards that define style in an attempt to make all code look as though it came from the same author. The notion is that it can then be more readily reviewed or enhanced by other team members. In a lot of cases, I question the value of these standards - at some point, you need to be able to read anyone else's code and the main impediment to that is hardly in the style.
There are also safety standards. For example, as I recall the MISRA standards, used in the automotive industry, advise against making variable declaration with statements such as the "for" statement. Again, the objective is to make the code more reviewable - especially in an environment where a bug could cost a life.
 
  • #11
jtbell said:
Someone will probably chime in about coding standards at many companies / organizations...
Sure, I've worked for three companies, in my current position, I help set the standard. Your professor is wrong, in the real world you're supposed to declare a variable in as small of a scope as possible. In C, it's traditional to declare all of your variables at the top of your program, that allows it to just move the stack pointer once, but that's because C didn't make much use of an optimizer. C++ uses an optimizing compiler, so it works better if you limit your variables to only the scope that they are needed in. You're professor's opinion is about a decade out of date.

This has been standard at all companies: DON'T REUSE VARIABLES! That's the biggest reason to declare it inline, to make sure that there isn't already an i somewhere.
 
  • #12
IIRC, C99 allowed declarations inside loops, in part, to help deal with "locality" issues. Commodity CPUs have "local" buffers with names like L2 or L1. Program code in those buffers can be accessed and executed quickly. Otherwise, the code from somewhere in slower RAM has to be accessed over and over again. The cost of accessing that code over and over again can be large when the code makes millions of iterations of a loop. Data may have the same problem, you can create a memory object that is too large to fit in the local buffers at one time. e.g. a gigantic array with millions of elements.

IF this sounds at all interesting try:
http://lwn.net/Articles/250967/ Start of the article there are 7 parts
http://lwn.net/Articles/252125/ Part that speaks to CPU caches.
 
  • #13
jk22 said:
Hence with the i defined only in the loop and the professor told me we shall never do that.

Do you know any reason ?
If you break out of the loop for some reason and you want to know afterwards if you did and for what value of i it happened, you may not be able to access a "localized" i. You can work around that, however, with a bit of thought and design before you code.

I must admit to being an old-fashioned ANSI C programmer, so an "inline" declaration does not seem natural to me.
 
  • #14
MISRA-C is a standard that is often applied to C code in airplanes and automobiles. The habit of declaring the index as you suggest would make it tempting to violate mandatory MISRA rule 21 (and maybe others):
"Identifiers in an inner scope shall not use the same name as an identifier in an outer scope, and therefore hide that identifier".

I am not sure what the history and rationalization of this rule is, but there is it and we often have to follow it.
(see http://home.sogang.ac.kr/sites/gsinfotech/study/study021/Lists/b7/Attachments/91/Chap%207.%20MISRA-C%20rules.pdf )

PS. I advise against using a generic loop index like i or j. Better is row_index, column_index, student_index, etc. whatever you are looping through.
 
Last edited by a moderator:
  • #15
FactChecker said:
PS. I advise against using a generic loop index like i or j. Better is row_index, column_index, student_index, etc. whatever you are looping through.
Agreed, i, j, x are nice and everyone uses them. It took me 10 years of writing code before I really got into the habit of explicitly naming variables like that, it's much easier to maintain later.
 
  • #16
In C++ in case you have same name variable in different scopes, the scope operator :: can be used. But it's true, using i,j,... is a bad habit, when writing small test codes maybe.
 
  • #17
From "Code Complete," by Steve McConnell,
Loop control variables in simple loops may have simple names. i, j, and k are customary.
...
If the variable is to be used outside the loop, it should be given a more meaningful name than than i, j, or k.
He also says that if the loop is longer than a few lines, or you have nested loops, it's better to use a more meaningful name for the loop index(es).
 
  • Like
Likes   Reactions: Jaeusm
  • #18
jk22 said:
In C++ in case you have same name variable in different scopes, the scope operator :: can be used. But it's true, using i,j,... is a bad habit, when writing small test codes maybe.
Only if you name the scopes, which isn't done very often.

Also, in a loop, you should use ++i instead of i++.
 
  • #19
newjerseyrunner said:
Also, in a loop, you should use ++i instead of i++.
That depends on the language. C and C++ are rather different languages, despite suggestions from management such as "We need to hire a C/C++ programmer!"

In C, the canonical form for a for loop is to use for (variable_name=initial; !final_condition; variable_name++)[ { ...} . Using ++variable_name in lieu of variable_name++ is a sign that the programmer may be doing something suspicious. It's exactly the opposite in C++. Using ++variable_name is the canonical form in C++; uing variable_name++ is a sign that something dubious might be happening.
 
  • #20
For the scope operator I thought naming were not mandatory ::i is just the previous scope ?

As for D H i didn't know that point just i read once about the border effect that since the stack of the arguments is reverse we could obtain weird results

i=10;
Prinft ("%d,%d.",i,++i)

Would print 11,11 ?
 
  • #21
jk22 said:
For the scope operator I thought naming were not mandatory ::i is just the previous scope ?
There is no way in C or C++ to access a hidden local variable. In C++, ::variable_name accesses the global variable of the given name in the global namespace. It does not provide access to some hidden local variable.
i=10;
Prinft ("%d,%d.",i,++i)

Would print 11,11 ?
There's no telling what that will print. The above code invokes undefined behavior. It might print 11,11. Then again, it might print 10,11. There's no telling. It might even make demons fly out of the programmer's nose (the so-called in nasal demons). The above could even result in a call to erase_hard_drive().
 
  • Like
Likes   Reactions: jk22
  • #22
I'm learned something new, but I'm a bit deceived, about the scope operator. I thought it was working hierarchically, going to outer and outer scope, so that we could have written ::i, ::::i, aso, but ::i directly access the global scope ?
 
  • #23
It doesn't work that way. Consider the following:
Code:
#include <iostream>
int ii = 1;
int main()
{
   int i = 2;
   { 
      int i = 3;
      std::count << "i=" << i << " ::i=" << ::i << "\n";
   } 
}
The above prints i=3 ::i=1 rather than i=3 ::i=2. The intermediate variable is inaccessible inside the inner block.

The C++ scope resolution operator (optional_namespace_name::variable_name) refers to the global variable named variable_name in the specified namespace. If the namespace is omitted, it refers to the global variable named variable_name in the global namespace. There is no way in C or in C++ to access a hidden local variable.

There's an easy way to solve the hidden variable problem: don't do it. The one exception might be constructors and setters for a class. Some people think the following is the epitome of good style:
Code:
class Foo {
private:
    int value;
public:
    Foo (int value) : value(value) {}
    void setValue(int value) { this->value = value; }
}
I'm not in that class of people that think the above is "good style." (In my humble opinion, it's anything but "good style.") A significant number people do think that way, however.Regarding the use of a local variable in a for loop (e.g, for (int i=0;i <100;i++) {...}), whoever told that that is "bad style" because of the local declaration is telling you something from a coding style that was born in and is best relegated to the previous millennium. The advice from the current millennium is that scoping your variables to the smallest scope possible is good style.
 
  • Like
Likes   Reactions: jim mcnamara
  • #24
So there is nothing like main::i=2 ?
 
  • #25
D H said:
That depends on the language. C and C++ are rather different languages, despite suggestions from management such as "We need to hire a C/C++ programmer!"

In C, the canonical form for a for loop is to use for (variable_name=initial; !final_condition; variable_name++)[ { ...} . Using ++variable_name in lieu of variable_name++ is a sign that the programmer may be doing something suspicious. It's exactly the opposite in C++. Using ++variable_name is the canonical form in C++; uing variable_name++ is a sign that something dubious might be happening.

I programmed in C for years and I've never heard this. It's not about canonical form or even personal preference, ++i and i++ literally mean different things and ++i is more efficient.
 
Last edited:
  • #26
newjerseyrunner said:
I programmed in C for years and I've never heard this. It's not about canonical form or even personal preference, ++i and i++ literally mean different things and ++i is more efficient.
++variable_name is not more efficient than variable_name++ with most compilers if the variable is of a primitive type and if the result isn't used. For example, the generated code for for (int i = 0; i < 42; i++) { do_something_with(i); } vs for (int i = 0; i < 42; ++i) { do_something_with(i); } will be identical with most compilers. The same goes with the byte code generated in Java. It's a difference that makes no difference in this case.Except it does make a difference in terms of readability. A typical C or Java programmer will look askew at someone who write for (int i = 0; i < 42; ++i) ... because the canonical form in those languages is to use post increment operator in such loops. In C++, the canonical form is to use pre-increment because of the potential large expense of making a copy of a non-primitive object.
 
  • Like
Likes   Reactions: .Scott and newjerseyrunner
  • #27
newjerseyrunner said:
Also, in a loop, you should use ++i instead of i++.
newjerseyrunner said:
It's not about canonical form or even personal preference, ++i and i++ literally mean different things and ++i is more efficient.
I agree wholeheartedly that they mean different things. As to efficiency, I have never noticed any difference.

Example of different results:

These snippets all do slightly different things!

while (destination++ = source++);
...
while (++destination= source++);
...
while (destination++ = ++source);
...
while (++destination= ++source);
...
 
  • #28
Svein said:
I agree wholeheartedly that they mean different things. As to efficiency, I have never noticed any difference.

Example of different results:

These snippets all do slightly different things!

while (destination++ = source++);
...
while (++destination= source++);
...
while (destination++ = ++source);
...
while (++destination= ++source);
...
You won't notice a difference with POD, and yeah, those while loops are all different (I assume you meant == instead of =, since none of those will actually compile :P)
 
  • #29
newjerseyrunner said:
You won't notice a difference with POD, and yeah, those while loops are all different (I assume you meant == instead of =, since none of those will actually compile :P)
Oh, yes they will! To make it slightly more difficult, I left out the declarations. Here they are:

char *destination, *source;

Hint: The first example does the same thing as strcpy(). The others do almost the same thing but with small errors.
 
  • #30
I've not tried, but some of them should and some of them should not. Here is the difference, these should compile.
Code:
while (++destination= source++);
while (++destination= ++source);
Here is why, you are first incrementing destination, then assigning it. This means that you have an actual variable to write to, because the address of (++destination) is the address of destination.

Code:
while (destination++ = source++);
while (destination++ = ++source);
Should not compile. What you are assigning to is the l-value and that's required to have an actual address. Here, (destination++) resolves to a temporary variable that has no scope and immediately vanishes, turn on -Wall on your compiler, and you should get an error. I'd frankly be a little surprised if you even needed the -Wall option.

strcpy is sort of like this, but with one very big difference. destination=source won't copy the character, it'l copy the pointer (*destination = *source) does a copy, notice that you must dereference the pointer and like I said destination++ has no pointer.
 

Similar threads

  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 16 ·
Replies
16
Views
3K
Replies
8
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 66 ·
3
Replies
66
Views
6K
  • · Replies 11 ·
Replies
11
Views
2K
  • · Replies 17 ·
Replies
17
Views
4K
  • · Replies 9 ·
Replies
9
Views
5K
  • · Replies 3 ·
Replies
3
Views
2K