I have always wondered if, in general, declaring a throw-away variable before a loop, as opposed to repeatedly inside the loop, makes any (performance) difference? A (quite pointless) example in Java:
a) declaration before loop:
double intermediateResult;
for(int i=0; i < 1000; i++){
intermediateResult = i;
System.out.println(intermediateResult);
}
b) declaration (repeatedly) inside loop:
for(int i=0; i < 1000; i++){
double intermediateResult = i;
System.out.println(intermediateResult);
}
Which one is better, a or b?
I suspect that repeated variable declaration (example b) creates more overhead in theory, but that compilers are smart enough so that it doesn't matter. Example b has the advantage of being more compact and limiting the scope of the variable to where it is used. Still, I tend to code according example a.
Edit: I am especially interested in the Java case.
Tried the same thing in Go, and compared the compiler output using
go tool compile -S
with go 1.9.4Zero difference, as per the assembler output.
It depends on the language and the exact use. For instance, in C# 1 it made no difference. In C# 2, if the local variable is captured by an anonymous method (or lambda expression in C# 3) it can make a very signficant difference.
Example:
Output:
The difference is that all of the actions capture the same
outer
variable, but each has its own separateinner
variable.I would always use A (rather than relying on the compiler) and might also rewrite to:
This still restricts
intermediateResult
to the loop's scope, but doesn't redeclare during each iteration.Even if I know my compiler is smart enough, I won't like to rely on it, and will use the a) variant.
The b) variant makes sense to me only if you desperately need to make the intermediateResult unavailable after the loop body. But I can't imagine such desperate situation, anyway....
EDIT: Jon Skeet made a very good point, showing that variable declaration inside a loop can make an actual semantic difference.
The following is what I wrote and compiled in .NET.
This is what I get from .NET Reflector when CIL is rendered back into code.
So both look exactly same after compilation. In managed languages code is converted into CL/byte code and at time of execution it's converted into machine language. So in machine language a double may not even be created on the stack. It may just be a register as code reflect that it is a temporary variable for
WriteLine
function. There are a whole set optimization rules just for loops. So the average guy shouldn't be worried about it, especially in managed languages. There are cases when you can optimize manage code, for example, if you have to concatenate a large number of strings using juststring a; a+=anotherstring[i]
vs usingStringBuilder
. There is very big difference in performance between both. There are a lot of such cases where the compiler cannot optimize your code, because it cannot figure out what is intended in a bigger scope. But it can pretty much optimize basic things for you.I made a simple test:
vs
I compiled these codes with gcc - 5.2.0. And then I disassembled the main () of these two codes and that's the result:
1º:
vs
2º
Which are exaclty the same asm result. isn't a proof that the two codes produce the same thing?