0

One of my students wrote this program to count up to 5, which I did not expect to work. I believed the target value of x would be overwritten with 0 when the loop begins, so the loop would either not start or run infinitely. Could someone please tell me what is going on behind the scenes?

Dim x As Integer
x = 5
For x = 0 To x
  MsgBox(x)
Next x
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
Drummy
  • 203
  • 1
  • 5
  • possible duplicate of [What is the difference between a reference type and value type in c#?](http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c) – Bjørn-Roger Kringsjå Oct 11 '14 at 14:37
  • It sort of has to do with `Block Scope`. The For loop start/stop values are initialized as new local variables limited to that block. If the loop used "j" instead, it would not be available outside the loop. That is Vb.NET - no idea about VB since that is closer to VB6; and relates to simple vars IEnumerable (as in iterating a collection) is different. – Ňɏssa Pøngjǣrdenlarp Oct 11 '14 at 14:47
  • @Plutonix That was my first thought too, but a bit of poking around led me to a different conclusion. – peterG Oct 11 '14 at 14:49
  • @peterG we are saying the same thing - `initialized as new local variables` == `target value is derived first` – Ňɏssa Pøngjǣrdenlarp Oct 11 '14 at 14:52
  • @Plutonix Yes I see what you mean. We're saying much the same thing, except that if you step through my version of the code, and hover the mouse over the 'Dim y as integer' line, it appears as though the variable y that's referenced within the loop is still the outer one; whereas if it were simply to do with scope, I'd expect the value of the 'outer y' would be independent of the 'inner y'. – peterG Oct 11 '14 at 15:10
  • 1
    Here's the first two lines when compiled to IL: 1) `.maxstack 3` 2) `.locals init ([0] int32 x, [1] int32 VB$t_i4$L0, [2] int32 VB$CG$t_i4$S0)` As you can see there are 3 local integers. The `X`, the `"from"` and the `"to"`. – Bjørn-Roger Kringsjå Oct 11 '14 at 15:16
  • @Bjørn-RogerKringsjå If I understand that correctly, yes, the from and to variables are local to the loop, but they're 'hidden', and they are set at the start of the loop and not modifiable from within. – peterG Oct 11 '14 at 15:25

4 Answers4

2

This is documented behavior, the relevant phrase in the MSDN documentation for the For statement:

Changing the value of counter while inside a loop can make it more difficult to read and debug your code. Changing the value of start, end, or step does not affect the iteration values determined when the loop was first entered.

The code generator accomplishes this by actually generating this code:

Dim x As Integer = 5
Dim $temp = x
For x = 0 To $temp
  MsgBox(x)
Next

Important behavior btw, not just to avoid coding accidents. Doing it this way allows the loop to be unrolled, one of the basic optimization strategies employed by the jitter.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

The target value is derived first, before the execution of the loop, and isn't touched thereafter. Compare this modified code; even though y is modified within the loop, its initial value is used as the target:

Module Module1
Sub main()
    Dim x As Integer
    x = 5
    Dim y As Integer
    y = 10

    For x = 0 To y
        MsgBox(x)
        y = y - 1
    Next x

End Sub
End Module
peterG
  • 1,651
  • 3
  • 14
  • 23
  • Looking at the (wrong) comments below the question itseld, I feel it must be clearly stated that this behaviour has nothing to do with variable scopes, with `x` being or not being local to the loop's body. Rather, it is a documented behaviour of VB and VB.NET that the expressions used to establish the `from`, `to` and `step` parameters of the `For` loop are always evaluated upfront, cached and not reevaluated during the loop. This is very different from e.g. C#, where the `for` loop evaluates its condition every time anew. – GSerg Oct 11 '14 at 15:38
0

Hope this would help :

'counter i.e. loop control variable x <> end i.e. final value of the counter x

'so start and end gets initialized, then control variable starting to change within that limit.

enter image description here

enter image description here

ZAT
  • 1,347
  • 7
  • 10
0

Thanks for all the comments; I think I have a better understanding now. The idea of 'block scope' was something I heard about many years ago but had completely forgotten. I had a little play with this in VB.NET and wrote 'For j = 1 to x', without explicitly declaring j. I was a little surprised to see this works in VB.NET, even with Option Explicit On. Hence block scope (and implicit block scope declaration) exists in practice - in VB. When I try to do the same in VBA, I get the error message 'Variable not defined'. All variables must be declared at least at procedure level. I presume there must be an extra local 'variable' that the compiler, or interpreter has given me for free, and this resides on the stack.

Drummy
  • 203
  • 1
  • 5