What is The Loop Variable After a For Loop in Delphi?
Asked Answered
F

7

9

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?

Fun answered 9/4, 2010 at 21:1 Comment(4)
Are you even certain that N is in scope after the for loop? I would check this first - because I suspect it may not be.Clasping
@LBushkin: That depends on how N is declared. But in the above code example I only use N as a "placeholder" for whatever might be the last value of the loop variable.Fun
@LBushkin, you can be absolutely certain that N will be in scope after the loop because it was obviously in scope before the loop (or else the code wouldn't have compiled). Scope in Delphi doesn't change mid-function; it starts at the start of a function and ends at the end.Filly
> But can you rely on this? - NOHumber
S
26

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.

Shred answered 9/4, 2010 at 21:27 Comment(10)
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 repeatShiff
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.Lederhosen
... 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).Scrapple
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.Filly
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.Blepharitis
@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).Apthorp
What happens if the compiler eliminates the variable as Bauer says and a break is encountered?Shred
@Deltics: Not necessarily moot, since the loop (and thus the exit) can be placed inside a try...finally block, and so upon executing exit you still have an opportunity to (try to) read the counter's value before leaving the procedure. Still, not a very common scenario, probably.Cene
@Andriy M: Yes, tho according to the current documentation it would imply that using BREAK or EXIT acts to guarantee the value of the counter variable: "After the for statement terminates (provided this was not forced by a BREAK or an EXIT procedure), the value of counter is undefined".Apthorp
@ldsandon: Previously it has been explained to me that if the counter variable is referenced in the loop then it will not be eliminated and that certainly corresponds with my experience. They couldn't change that behaviour (no matter what the documentation may or may not ever have actually said) without risking breaking a lot of existing code.Apthorp
G
7

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

Gamali answered 9/4, 2010 at 21:24 Comment(0)
L
6

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).

Latrinalatrine answered 9/4, 2010 at 21:5 Comment(2)
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".Fun
You could use Inc(i) instead of i := i + 1, but IIRC the compiler will treat them the same anyway.Intercommunion
A
2

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

Anemo answered 9/4, 2010 at 21:42 Comment(0)
C
1

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.

Cupped answered 9/4, 2010 at 21:45 Comment(0)
H
1

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).
Humber answered 27/5, 2010 at 21:5 Comment(6)
Well, this is perhaps a bit too "strict". For instance, in many cases the warning "return value of function ... might be undefined" is irrelevant.Fun
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.Tawnytawnya
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.Fun
"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.Humber
"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? :)Humber
@Altar: Yes, that is actually a gain by itself. It also makes the more serious issues easier to spot in the log.Fun
B
0

As its been stated before, its undefined and can behave funnily if the variable has a value assigned before the for loop. If you exit the for loop with a Break; then the value is correct in all cases.

In our experience, in FreePascal, the value of the loop variable tends to be the "to" value, but in embarcadero (former borland), the value is often "to" + 1.

I wonder why no pascal compiler gives you even a warning regarding this issue, as its going to cause certain mayhem.

Bate answered 31/7 at 12:23 Comment(2)
Actually, most Delphi compilers give you such a warning: docwiki.embarcadero.com/RADStudio/en/…Blepharitis
@Blepharitis Thanks for the tip, Free Pascal / Lazarus does not warn you.Bate

© 2022 - 2024 — McMap. All rights reserved.