Bug in VB.NET Compiler (easy to reproduce).

M

Mark Walsh

The following is an explanation of a bug that exists in the VB.NET compiler.
I've tried to report it to Microsoft, but they've made it so difficult I've
given up:

MSDN help states that variables are initialised when they are created. This
seems to be true for the following code which produces "1","2","3","4","5".
(ie the variable is created when a procedure is entered and not when
for-loop is entered)

For i = 1 To 5
Dim x As Integer
x += 1
MsgBox(x.ToString)
Next

However, this is INCONSISTENT with the following code:

For i = 1 To 5
Dim x As Integer = 0
x += 1
MsgBox(x.ToString)
Next

which displays "1","1","1","1","1" implying that the variable is re-created
(if I believe the help) and consequently re-initialised each time the loop
iterates (ie: when it comes into scope, not when it is created)


If you disassemble a piece of code you will see that variables are created
when the PROCEDURE is entered NOT when a block (eg a "for loop") is entered:

For Example, the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim W As Integer = 2
Dim A As Integer = 3
Dim C As Integer = 4
Dim R As Integer = 5
Dim T As Integer = 6
Dim F As Integer = 7

For i = 1 To 5
Dim x1 As Integer = 0
Dim x2 As Integer = 0
Dim x3 As Integer = 0
Dim x4 As Integer = 0
Dim x5 As Integer = 0
Dim x6 As Integer = 0
x1 += 1
Next
End Sub

Disassembles as:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,3Ch
00000006 push edi
00000007 push esi
00000008 push ebx
00000009 mov dword ptr [ebp-4],ecx
0000000c mov dword ptr [ebp-8],edx
0000000f xor ebx,ebx
00000011 mov dword ptr [ebp-10h],0
00000018 mov dword ptr [ebp-14h],0
0000001f xor esi,esi
00000021 mov dword ptr [ebp-1Ch],0
00000028 mov dword ptr [ebp-20h],0
0000002f mov dword ptr [ebp-24h],0
00000036 xor edi,edi
00000038 mov dword ptr [ebp-2Ch],0
0000003f mov dword ptr [ebp-30h],0
00000046 mov dword ptr [ebp-34h],0
0000004d mov dword ptr [ebp-38h],0
00000054 mov dword ptr [ebp-3Ch],0
0000005b nop
Dim W As Integer = 2
0000005c mov dword ptr [ebp-24h],2
Dim A As Integer = 3
00000063 mov ebx,3
Dim C As Integer = 4
00000068 mov dword ptr [ebp-10h],4
Dim R As Integer = 5
0000006f mov dword ptr [ebp-1Ch],5
Dim T As Integer = 6
00000076 mov dword ptr [ebp-20h],6
Dim F As Integer = 7
0000007d mov dword ptr [ebp-14h],7
For i = 1 To 5
00000084 mov esi,1
Dim x1 As Integer = 0
00000089 xor edi,edi
Dim x2 As Integer = 0
0000008b mov dword ptr [ebp-2Ch],0
Dim x3 As Integer = 0
00000092 mov dword ptr [ebp-30h],0
Dim x4 As Integer = 0
00000099 mov dword ptr [ebp-34h],0
Dim x5 As Integer = 0
000000a0 mov dword ptr [ebp-38h],0
Dim x6 As Integer = 0
000000a7 mov dword ptr [ebp-3Ch],0
x1 += 1
000000ae add edi,1
000000b1 jno 000000BA
000000b3 xor ecx,ecx
000000b5 call 7847D2B4
Next
000000ba nop
000000bb add esi,1
000000be jno 000000C7
000000c0 xor ecx,ecx
000000c2 call 7847D2B4
000000c7 cmp esi,5
000000ca jle 00000089
End Sub

Notice that on line 00000092 for example (the code for Dim x3 As Integer =
0) that it is assigning zero to an address pointed to by register ebp-30h.
In other words the variable has already been created on the stack when the
procedure was entered, not when the loop is entered. This assignment is at
complete odds with the help which says that initialisation happens when a
variable is created.

The above behaviour is also inconsistent with the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Static x As Integer = 3
Dim i As Integer
For i = 1 To 5
x += 1
Next
MsgBox(x.ToString)
End Sub

The above piece of code displays '8' the first time the procedure is
entered, and 13 the second time the procedure is entered. STATIC X is only
created once (the first
time the procedure is entered) and initialised once, when the variable is
created. Not every time the variable comes into scope.



"this behaviour is by design" ... I hope not, it's a shocker.

Mark (KAZ technology services, Australia).
 
T

Tom Leylan

Hi Mark... I hope your message isn't intended to start an argument... but
the behavior seems entirely consistent to me. In fact it is defined as
behaving as you describe... I'll guess that you want the assignment (of
zero) to only happen once but it doesn't, it happens inside the loop.

From the help file: "Note Even if the scope of an element is limited to a
block, its lifetime is still that of the entire procedure. If you enter the
block more than once during the procedure, a block variable retains its
previous value. To avoid unexpected results in such a case, it is wise to
initialize the variable each time."

This works as you described:
For i = 1 To 5
Dim x As Integer
x += 1
MsgBox(x.ToString)
Next

And so does this:
However, this is INCONSISTENT with the following code:

For i = 1 To 5
Dim x As Integer = 0
x += 1
MsgBox(x.ToString)
Next

which displays "1","1","1","1","1" implying that the variable is re-created
(if I believe the help) and consequently re-initialised each time the loop
iterates (ie: when it comes into scope, not when it is created)

And so is this:
If you disassemble a piece of code you will see that variables are created
when the PROCEDURE is entered NOT when a block (eg a "for loop") is
entered:


And the following code is consistent with the behavior of statically
declared variables.
 
M

Mark Walsh

Thanks for taking the time to reply.

Initialisation and assignment are two different things yes? Initialisation
happens when a variable is allocated memory and only happens once. With
reference to my previous post, a statement like:

"dim x as integer = 0" inside a loop (for VB.NET) results in assignment not
initialisation. (x is assigned a new value for each loop iteration)

Whereas the statement "Static x integer=0" in a procedure results in
initialisation not assignment (x is not assigned a new value each time the
procedure is entered)

See the inconsistency?
 
S

Scott M.

Mark Walsh said:
Thanks for taking the time to reply.

Initialisation and assignment are two different things yes? Initialisation
happens when a variable is allocated memory and only happens once. With
reference to my previous post, a statement like:

"dim x as integer = 0" inside a loop (for VB.NET) results in assignment not
initialisation. (x is assigned a new value for each loop iteration)

Actually, this is an assigment (=0) and an initialization (Dim x as
Integer). You are doing both with this one line of code.

The fact that it is in a loop just means that it gets RE-assigned and
RE-initialized each time the loop runs.

Now, if you wrote the line like this:

Dim x as Integer 'This is just the initialization
x =0 'This is the assignment
 
T

Tom Leylan

Mark Walsh said:
"dim x as integer = 0" inside a loop (for VB.NET) results in assignment not
initialisation. (x is assigned a new value for each loop iteration)

Whereas the statement "Static x integer=0" in a procedure results in
initialisation not assignment (x is not assigned a new value each time the
procedure is entered)

Hi Mark... that's much clearer (short and sweet worked) thanks. I agree
that the "syntax" is somewhat inconsistent but not the "behavior." By that
I mean we're stuck with certain facts. Static variables have been used for
decades and changing the way they work would have been a huge mess so
consider the syntax and behavior of them, "fixed and unchangeable."

So now we have block scope. It has a defined behavior too. Slightly
different than the one for static variables but it has unique requirement.
They can't change the syntax/behavior of static variables so how would you
propose the syntax for block scope should read?

The situation isn't entirely unlike how "remove" can have two meanings.
Remove an item from a list, remove a file from the disk drive. The syntax
is identical but the behavior is different. Static variables aren't block
scoped or they would behave the same.

So... yes there is a bit of inconsistency but clearly not a "bug" and so far
as I can see it's due to having to choose some sort of syntax for
declaration and some sort of syntax for assignment. I guess I'm back to
"what else could it look like?" :)

Tom
 
C

Cor

Hi Tom,
So... yes there is a bit of inconsistency but clearly not a "bug" and so far
as I can see it's due to having to choose some sort of syntax for
declaration and some sort of syntax for assignment.

I agree with you, of course no bug and how to overcome a once decided
situation that is already implemented and used, but it is an inconsitency
that needs very good documentation I think.

Cor
 
M

Mark Walsh

Hi Tom,

It's not something that microsoft would want to change because to many
programmers already rely on this behaviour, but to make it consistent, a
loop like:

for i =1 to 5
dim x as integer
dim y as integer = 0

x +=1
y+=1

loop

should produce the same output for both x and y, even though x is
auto-initialised (ie x and y are both initialised when they are allocated,
not every time they go around the loop) . They are in fact both allocated on
the stack at the same time and should be initialised at the same time, the
same way.
 
T

Tom Leylan

Hi Mark,

I don't know... we need both behaviors to be available. I just wrote some
code using block-scoped vars the other day and I needed them reset inside
the loop. On the other hand if you didn't want them reinitialized inside
the loop you would use the syntax in your first example.

It's doing two things. Primarily it is declaring the visibility (and
datatype of course) of the variable and second it permits you (optionally)
to assign a value to the variable. I think you would be happier if it
looked like the following... but that pretty much just makes me type one
extra line and either it would have to prevent the assignment during
declaration or as you suggest it could move the assignments to the point of
initialization. The trouble with that I would guess is that while they are
on the stack, as you point out, they aren't "visible" by definition and you
shouldn't be able to assign values to them.

for i =1 to 5
dim x as integer
dim y as integer
y = 0

x +=1
y+=1
loop

There would have to be a defined behavior for somethink like the following
also:

for i =1 to 5
dim x as integer = 2
dim y as integer = x

x +=1
y+=1
loop

I'm certain it could be made to work but again "X" isn't really supposed to
be visible until it gets inside the for loop and Y is supposed to get the
value of X assigned each time it enters the for loop.

I'll admit that it might be counter-intuitive but it works (that's always a
good sign) and it can be ignored (use of block-scopevars isn't required) or
it can be memorized like having to add the word "loop" rather than "next"
:)

In the end it's just syntax... like why didn't they add X++ and ++X
increment (and decrement) operator syntax for gosh sake?

Take care,
Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top