Declaring Variables Inside Loops, Good Practice or Bad Practice

Declaring variables inside loops, good practice or bad practice?

This is excellent practice.

By creating variables inside loops, you ensure their scope is restricted to inside the loop. It cannot be referenced nor called outside of the loop.

This way:

  • If the name of the variable is a bit "generic" (like "i"), there is no risk to mix it with another variable of same name somewhere later in your code (can also be mitigated using the -Wshadow warning instruction on GCC)

  • The compiler knows that the variable scope is limited to inside the loop, and therefore will issue a proper error message if the variable is by mistake referenced elsewhere.

  • Last but not least, some dedicated optimization can be performed more efficiently by the compiler (most importantly register allocation), since it knows that the variable cannot be used outside of the loop. For example, no need to store the result for later re-use.

In short, you are right to do it.

Note however that the variable is not supposed to retain its value between each loop. In such case, you may need to initialize it every time. You can also create a larger block, encompassing the loop, whose sole purpose is to declare variables which must retain their value from one loop to another. This typically includes the loop counter itself.

{
int i, retainValue;
for (i=0; i<N; i++)
{
int tmpValue;
/* tmpValue is uninitialized */
/* retainValue still has its previous value from previous loop */

/* Do some stuff here */
}
/* Here, retainValue is still valid; tmpValue no longer */
}

For question #2:
The variable is allocated once, when the function is called. In fact, from an allocation perspective, it is (nearly) the same as declaring the variable at the beginning of the function. The only difference is the scope: the variable cannot be used outside of the loop. It may even be possible that the variable is not allocated, just re-using some free slot (from other variable whose scope has ended).

With restricted and more precise scope come more accurate optimizations. But more importantly, it makes your code safer, with less states (i.e. variables) to worry about when reading other parts of the code.

This is true even outside of an if(){...} block. Typically, instead of :

    int result;
(...)
result = f1();
if (result) then { (...) }
(...)
result = f2();
if (result) then { (...) }

it's safer to write :

    (...)
{
int const result = f1();
if (result) then { (...) }
}
(...)
{
int const result = f2();
if (result) then { (...) }
}

The difference may seem minor, especially on such a small example.
But on a larger code base, it will help : now there is no risk to transport some result value from f1() to f2() block. Each result is strictly limited to its own scope, making its role more accurate. From a reviewer perspective, it's much nicer, since he has less long range state variables to worry about and track.

Even the compiler will help better : assuming that, in the future, after some erroneous change of code, result is not properly initialized with f2(). The second version will simply refuse to work, stating a clear error message at compile time (way better than run time). The first version will not spot anything, the result of f1() will simply be tested a second time, being confused for the result of f2().

Complementary information

The open-source tool CppCheck (a static analysis tool for C/C++ code) provides some excellent hints regarding optimal scope of variables.

In response to comment on allocation:
The above rule is true in C, but might not be for some C++ classes.

For standard types and structures, the size of variable is known at compilation time. There is no such thing as "construction" in C, so the space for the variable will simply be allocated into the stack (without any initialization), when the function is called. That's why there is a "zero" cost when declaring the variable inside a loop.

However, for C++ classes, there is this constructor thing which I know much less about. I guess allocation is probably not going to be the issue, since the compiler shall be clever enough to reuse the same space, but the initialization is likely to take place at each loop iteration.

What's the best practice to declare a variable in Dart?

The scope of a local variable should be as small as possible. Thus, declaring a variable inside the loop is a better practice.

The advantages of doing so:

  • Avoids mixing up of variables having generic names: if a variable is named i and the same variable is referenced in multiple loops, it may get confusing as to what value the variable holds at any part of the program.
  • Compiler issues precise warnings and errors if this local variable gets referenced somewhere else
  • Better optimizations: as the local variable scope is limited to the loop, so no need to store the variable value after the loop is executed. For today's standards, this little optimization doesn't matter much though.
  • Better readability

Declaring variable inside the loop is good only if you do not need to reuse the updated variable value like:

int counter = 0;
for(final i in range(1, 10)) {
counter++;
// use variable counter here as a "counter"
}

In the snippet below, using the variable counter as a counter is invalid as the variable is reinitialized at the start of each loop

for(final i in range(1, 10)) {
int counter = 0;
counter++;
// use counter here as a "counter"
}

If you do want to use a variable as a counter(or any other purpose) and update its value inside a loop and use it outside of the scope of the loop then only declare the variable outside of the loop.

Refrences:

  • Declaring variables inside loops, good practice or bad practice?
  • Declaring variables inside or outside of a loop

declare variable inside or outside a loop, does it make big difference?

Yes. scope of variable i is different in both cases.

In first case, A variable i declared in a block or function. So, you can access it in the block or function.

In the second case, A variable I declared in a while loop. So, you can access it in while loop only.

Does it make big difference in terms of performance?

No, it will not matter performance-wise where you declare it.

For example 1:

int main()
{
int i, bigNumber;

while(bigNumber--) {
i = 0;
}
}

Assembly:

main:
push rbp
mov rbp, rsp
.L3:
mov eax, DWORD PTR [rbp-4]
lea edx, [rax-1]
mov DWORD PTR [rbp-4], edx
test eax, eax
setne al
test al, al
je .L2
mov DWORD PTR [rbp-8], 0
jmp .L3
.L2:
mov eax, 0
pop rbp
ret

Example 2:

int main()
{
int bigNumber;

while(bigNumber--) {
int i;
i = 0;
}
}

Assembly:

main:
push rbp
mov rbp, rsp
.L3:
mov eax, DWORD PTR [rbp-4]
lea edx, [rax-1]
mov DWORD PTR [rbp-4], edx
test eax, eax
setne al
test al, al
je .L2
mov DWORD PTR [rbp-8], 0
jmp .L3
.L2:
mov eax, 0
pop rbp
ret

Both generate the same assembly code.

Does declaring a variable inside a loop body have any disadvantages?

Conceptually that variable is constructed and destructed on each iteration.

But does it affect performance? Well, you can check your case right here. Delete int on line 7 to switch between the loop-local and function-local variables.

Conclusion: no difference whatsoever. The assembly is the same!

So, just use what makes sense in your code. If you need one object per iteration, make one object per. The optimizer is smarter than you think. If that wasn't enough, you'd come back to it with profiling data and careful tweaking, not broad guidelines.

What is the good practice to declare loop variables?

You said:

the variable i is declared on every iteration of the loop! These re-declarations consume more processing power and re-allocation of memory again and again

This is an invalid assumption on your part. The C compiler will calculate the total memory the function needs and allocate for that usage up front. For local variables, that allocation is actually just a shift of a pointer.

To illustrate, if I have a function:

void a_function () {
extern int x, n1, n2;

while (--n1) {
int i;
scanf("%d", &i);
x += i;
}

while (--n2) {
int i, j;
scanf("%d %d", &i, &j);
x += i + j;
}
}

The compiler will allocate space for 2 integers on entry into the function (or none, if it decides it can do everything in registers).

Does It Matter If I Declare A Variable Inside A Loop?

Yes, it does matter. In second case

int count=0;
while(count<10)
int a=0;

a can't be referenced out side of while loop. It has block scope; the portion of the program text in which the variable can be referenced.

Another thing that Jonathan Leffler pointed out in his answer is both of these loops are infinite loop. And second, the most important second snippet would not compile without {} (in C) because a variable definition/declaration is not a statement and cannot appear as the body of a loop.

 int count  =0;
while(count++ < 10)
{
int a=0;
}


Related Topics



Leave a reply



Submit