I have the following code:
function p (str)
Response.Write VBLF & str
end function
function nop: end function
class Test1
private sub class_initialize
p "Test1 Start"
end sub
private sub class_terminate
p "Test1 End"
end sub
end class
class Test2
private sub class_initialize
p " Test2 Start"
end sub
private sub class_terminate
p " Test2 End"
end sub
end class
When I run:
with new Test1
with new Test2
end with
end with
I expect the output:
Test1 Start
Test2 Start
Test2 End
Test1 End
But I get:
Test1 Start
Test2 Start
Test1 End
Test2 End
I do, however, get what I expected if I run either of the following:
with new Test1
with new Test2
nop
end with
end with
with new Test1
with new Test2
end with
nop
end with
But not the following:
with new Test1
nop
with new Test2
end with
end with
VBScript has a fairly strong guarantee about GC'ing objects right away, and I'm using (abusing?) this guarantee for a variety of purposes in my applications. Without the nop
, why is it collecting Test1
and Test2
in the "wrong" order?
What a fascinating bug.
I do not have a debug build of the VBScript engine handy. (The ten year old hard disk that I was keeping it on has apparently gone bad some time in the two years since I last looked at it.) However, I can easily guess what is going on here. My suspicion is that I did not mark the instruction corresponding to the "end with" as a point at which a statement has ended and the collector must run.
Let's consider that hypothesis.
In your first example, when would the GC run? When the program ends. At that point, the terminators are run in the order that the objects were created. (This is an implementation detail that you should not rely upon.)
In your second and third example the end of the call to nop triggers a GC, and that happens right next to the end with. (I'm not quite sure why the second example triggers a GC when the object is eligible for collection; I don't recall the exact semantics of the codegen for popping the object reference out of the with block scope.)
In your fourth example, the GC is triggered before the inner with, and does nothing.
Since I wrote both the termination logic and a fair amount of the "with" processing code I undoubtedly caused this bug, so many apologies. Since apparently we've lived with it with no major problems for the last eleven or twelve years, and since it only affects "with" blocks that have no contents, I don't imagine it will ever be fixed.
Regardless, you should not rely on termination order. That's a bad programming practice.
For more on the fascinating subject of VBScript termination logic see:
What is the order of destruction of objects in VBScript?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With