views:

447

answers:

6

In Delphi, consider

var
  i: integer;

begin

  for i := 0 to N do
  begin
    { Code }
  end;

One might think that i = N after the for loop, but does the Delphi compiler guarantee this? Can one make the assumption that the loop variable is equal to its last value inside the loop, after a Delphi if loop?

Update

After trying a few simple loops, I suspect that i is actually equal to one plus the last value of i inside the loop after the loop... But can you rely on this?

+6  A: 

I would suggest that using a while loop is clearer if you need to use the loop index after the loop:

i := 0;
while i <= N
begin
    { Code }
    i := i + 1;
end;

After that loop terminates, you know that i will be N + 1 (or greater, if N could have been less than zero).

Greg Hewgill
Yes, that is a very good method. After all, every for loop can be written as a while loop in this way, but without any "compiler magic".
Andreas Rejbrand
You could use `Inc(i)` instead of `i := i + 1`, but IIRC the compiler will treat them the same anyway.
Gerry
+6  A: 

The compiler actually emits a warning if you use the loop variable after the loop, so you should consider it undefined.

Giel
+18  A: 

No, Delphi does not guarantee any value. Outside the loop, the variable is undefined - and IIRC the Language Guide excplicitly state so - that means that newer compiler implementations are free to change whatever value the variable may have outside the loop due to the actual implementation.

ldsandon
That is correct. The variable is specifically documented to be undefined after the loop is complete. If you need a defined variable after the loop, use while or repeat
Nick Hodges
Depending upon how the loop variable is used within the loop, the compiler may even eliminate it completely and simply use a pointer to iterate through the elements of an array, for example.
Allen Bauer
+1 since Nick said you're correct!
Chris Thornton
... is undefined ... except if you terminate the loop with the 'break' statement. In that case, value is defined (the last value the loop counter had before the 'break' was executed).
gabr
Gabr is right. If you leave the loop with `break`, the control variable's value will be valid. Likewise if you leave the loop with `exit`. The documentation says so. Undocumented, but still generally accepted as true, is that leaving the loop via `raise` or `goto` will also preserve the variable's value.
Rob Kennedy
If the variable isn't used inside the loop, the compiler might generate code that counts from N to 0 even if the source says to count from 0 to N, because that is slightly more efficient. I have no idea what value the variable would have after the loop in that case.
dummzeuch
@Chris: Nick was however slightly wrong. The counter variable *is* defined if the loop is terminated by a BREAK or EXIT (though with an EXIT the validity of the counter variable is moot since the code following the loop won't execute as the flow of control will leave the procedure containing the simple local variable that a for loop counter demands).
Deltics
What happens if the compiler eliminates the variable as Bauer says and a break is encountered?
ldsandon
+1  A: 

It is even documented that the loop variable from a for loop is undefined outside the loop.

In practice: What you get from the variable varies depending on compiler settings and code complexity. I have seen changes in code push the compiler into a different optimization path, therefore modifying the value of this undefined variable.

--jeroen

Jeroen Pluimers
+1  A: 

As many people stated, the I variable is supposed to be undefined after the loop. In real world usage, it will be defined to the last value it had before you "break", or to N + 1 if loop run to term. That behavior cannot be relied on though, as it's clearly specified it's not meant to work.

Also, sometimes, I won't even be assigned. I encountered this behavior mostly with optimisation turned ON.

For code like this

I := 1234;
For I := 0 to List.Count - 1 do
begin
  //some code
end;
//Here, I = 1234 if List.Count = 0

So... If you want to know the value of I after the loop, it's better practice to assign it to another variable before going out of the loop.

Ken Bourassa
A: 

NEVER EVER rely on the value of the for variable, after the loop.

Check your compiler output. Delphi compiler warns you about that. Trust your compiler.

  1. NEVER hide your compiler's hints and warnings with {$Warnings off}!
  2. Learn to treat the info as warnings and the warnings as errors!
  3. Optimize your code until you have ZERO hints and warnings (without violating rule 1).
Altar
Well, this is perhaps a bit too "strict". For instance, in many cases the warning "return value of function ... might be undefined" is irrelevant.
Andreas Rejbrand
It's very rare that the compiler says something may be undefined when that's not possible. The only cases I've seen involve two conditionals that assign results and inherently one of them must run. I consider it worth a bit of extra code to suppress *ALL* warnings even when I know they are harmless.
Loren Pechtel
This happens often if you `raise` an exception inside the function, or if you mix the `Exit(ReturnValue)` method with the old-school `result :=` method.
Andreas Rejbrand
"For instance, in many cases the warning "return value of function ... might be undefined" is irrelevant" - learn to initialize that variable. Anyway, these case are not so many.
Altar
"I consider it worth a bit of extra code to suppress ALL warnings even when I know they are harmless." - Isn't nice to have a clean compiler output? :)
Altar
@Altar: Yes, that is actually a gain by itself. It also makes the more serious issues easier to spot in the log.
Andreas Rejbrand