-
Jan 14th, 2022, 07:39 PM
#1
Nested Collection Iterations
Ok, I've got a collection of objects I'm iterating in a loop. Specifically, they're Node objects (TreeView).
Now, inside my iteration loop, I'd like to pass the whole collection to another procedure, and possibly iterate it down in that other procedure.
When I return, I want my higher-level iteration to pick up where it left off.
Is there a problem with this? I'll be running tests while waiting on a reply.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 14th, 2022, 07:46 PM
#2
Re: Nested Collection Iterations
Hmmm, ok, it seems to work just fine. My test....
For a quick class (Class1):
Code:
Option Explicit
Public s As String
My test in Form1:
Code:
Option Explicit
Private Sub Form_Load()
Dim c As New Collection
Dim o As Class1
Set o = New Class1: o.s = "001": c.Add o
Set o = New Class1: o.s = "002": c.Add o
Set o = New Class1: o.s = "003": c.Add o
Set o = New Class1: o.s = "004": c.Add o
Set o = New Class1: o.s = "005": c.Add o
For Each o In c
Debug.Print o.s
Test c
Next
End Sub
Sub Test(c As Collection)
Dim o As Class1
For Each o In c
Debug.Print " nested: "; o.s
Next
End Sub
And my Immediate Window output:
Code:
001
nested: 001
nested: 002
nested: 003
nested: 004
nested: 005
002
nested: 001
nested: 002
nested: 003
nested: 004
nested: 005
003
nested: 001
nested: 002
nested: 003
nested: 004
nested: 005
004
nested: 001
nested: 002
nested: 003
nested: 004
nested: 005
005
nested: 001
nested: 002
nested: 003
nested: 004
nested: 005
Ok, so I guess my question changes to: Am I asking for any trouble when doing this?
EDIT: I guess it's my lack of full understanding of the (under the hood) stuff of iterations that's got me worried. There's obviously some index-pointer somewhere that's keeping track of where the iteration is. I was just worried about what happens to that pointer when there's a sub-iteration.
Does it use the actual object (in the example above, the "o" variable) to reference itself and find the next one? That's definitely how a "For i = a to b" loop works. If that's so, I should be able to change the object variable (used for iteration) and make the loop prematurely terminate. I'll test that now.
.
Last edited by Elroy; Jan 14th, 2022 at 07:54 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 14th, 2022, 08:02 PM
#3
Re: Nested Collection Iterations
Nope, it's not using the iteration variable for the pointer. Proof:
(Same Class1 from above.)
In a Form1:
Code:
Option Explicit
Private Sub Form_Load()
Dim c As New Collection
Dim o1 As Class1
Set o1 = New Class1: o1.s = "001": c.Add o1
Set o1 = New Class1: o1.s = "002": c.Add o1
Set o1 = New Class1: o1.s = "003": c.Add o1
Set o1 = New Class1: o1.s = "004": c.Add o1
Set o1 = New Class1: o1.s = "005": c.Add o1
' Ok, right now, o1 is the last item added.
' But let's make sure.
Debug.Print "Right now, o1: "; o1.s
Dim o2 As Class1
For Each o2 In c
Debug.Print o2.s
If o2.s = "002" Then Set o2 = o1
Next
Debug.Print "dropped out"
End Sub
And my Debug output:
Code:
Right now, o1: 005
001
002
003
004
005
dropped out
If it was using the iterator variable (o2 in this case), then my output should have looked like this (but it didn't):
Code:
Right now, o1: 005
001
002
dropped out
So, I just really don't know how iteration loops work. I know how to use them, but it'd be nice to have a deeper understanding.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 15th, 2022, 10:29 AM
#4
Re: Nested Collection Iterations
..
I've been thinking about it, and I still don't "get" it. I mean, we're not talking about different instantiations. We're talking about different references to the same object (the collection). And, I thought a reference was nothing more than a four-byte (for 32-bit) pointer (basically an alias) to the actual COM object. So, I don't see how an iteration pointer could be stored with the reference variable.
Now sure, the COM object has a counter in it that keeps track of how many references there are to it (uninstantiating the COM object when that counter goes to zero). In fact, I'm sure there's lots of header information in these COM object, the vTable, etc, etc. But, there's still just one object and one counter and one header. How can these iteration pointers be in the actual COM object? Is there some array of them in the COM object? Is there a limit to how deeply we can do this nested iterating?
Hmmm, I guess another possibility is that an iteration loop sets up its own internal (invisible) variable/header and keeps track of things on its own. That almost has to be the answer. I just don't see another reasonable way. But then, that makes me wonder how these iteration loops are cleaned up if/when you jump out of the middle of them. For a typical For i = a To b loop, there's nothing really to clean up.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 15th, 2022, 11:31 AM
#5
Re: Nested Collection Iterations
"For each" cycle for objects is based on the IEnumVariant interface. So when you initiate a loop the runtime requests for an IEnumVariant enumerator object (through DISPID_NEWENUM request). This object usually is a different object which has its own state like the current item etc. "For each" loop works with this hidden object so it doesn't matter how you change your iterated variable. Notice the iteration variable should be inherited from IDispatch interface.
-
Jan 15th, 2022, 12:37 PM
#6
Re: Nested Collection Iterations
Try this
Code:
If o2.s = "002" Then
c.Add o1
End If
The VBA.Collection enumerator does see changes to the linked list of the base object.
It's possible to implement an enumerator which snapshots the linked list initially and is not affected (does not see) any mutation of the base container (e.g. ADODB.Fields -- not sure actually, just a possibility).
In every For Each statement there is an unsung hero being the enumerator object which is completely missing from public typelibs and is known in the world only through its IEnumVARIANT interface :-))
cheers,
</wqw>
-
Jan 15th, 2022, 06:34 PM
#7
Re: Nested Collection Iterations
Thank you, Trick & Wqweto. That explains it. It seems my last "guess" was fairly close, "another possibility is that an iteration loop sets up its own internal (invisible) variable/header and keeps track of things on its own". And with y'all's information, I can go study the IEnumVARIANT interface and DISPID_NEWENUM when/if I want to know more.
This also explains why I can delete items in a For Each loop and it doesn't get confused.
Wqweto, that "snapshot" explanation may come in very handy in the future.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 09:33 AM
#8
Re: Nested Collection Iterations
My, in the meanwhile, quite old code for a hierarchical tree structure.
Nothing fancy, does it's job ;-)
The Tree class
Code:
'---------------------------------------------------------------------------------------
' Module : clsTree
' DateTime : 25-10-2006
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Option Explicit
Private m_cNodes As Collection
Private m_cKeys As Collection
Private m_lKeyCnt As Long
'---------------------------------------------------------------------------------------
' Procedure : Add
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Adds a treenode to the tree
' : ParentKey and Key can be empty
'---------------------------------------------------------------------------------------
Public Function Add(sParentKey As String, sKey As String, sText As String) As clsTreeNode
Dim myNode As clsTreeNode
Dim myParent As clsTreeNode
If Exists(sKey) Then Exit Function
If Len(sParentKey) > 0 Then If Not Exists(sParentKey) Then Exit Function
m_lKeyCnt = m_lKeyCnt + 1
Set myNode = New clsTreeNode
myNode.Key = sKey
myNode.Text = sText
myNode.UniqueKey = "key:" & m_lKeyCnt
If Len(sParentKey) > 0 Then
Set myParent = m_cNodes(m_cKeys(sParentKey))
' Add as child to parent
myParent.AddChild myNode
' Set current parent of child
Set myNode.Parent = myParent
End If
m_cNodes.Add myNode, myNode.UniqueKey
If Len(sKey) > 0 Then
m_cKeys.Add myNode.UniqueKey, sKey
End If
Set Add = myNode
Set myNode = Nothing
End Function
'---------------------------------------------------------------------------------------
' Procedure : TreeNode
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Returns the TreeNode or Nothing, based on the Key
'---------------------------------------------------------------------------------------
Public Property Get TreeNode(sKey As String) As clsTreeNode
Set TreeNode = pTreeNode(sKey)
End Property
'---------------------------------------------------------------------------------------
' Procedure : TreeNodeIndex
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Returns the TreeNode or Nothing, based on the index
'---------------------------------------------------------------------------------------
Public Property Get TreeNodeIndex(ByVal lIndex As Long) As clsTreeNode
If lIndex > 0 And lIndex <= m_cNodes.Count Then
Set TreeNodeIndex = m_cNodes(lIndex)
End If
End Property
'---------------------------------------------------------------------------------------
' Procedure : Exists
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Returns whether a node for a given key exists in the tree
'---------------------------------------------------------------------------------------
Public Function Exists(sKey As String) As Boolean
If Len(sKey) > 0 Then
Exists = Not (pTreeNode(sKey) Is Nothing)
End If
End Function
'---------------------------------------------------------------------------------------
' Procedure : Count
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Returns the number of nodes in the tree
'---------------------------------------------------------------------------------------
Public Function Count() As Long
Count = m_cNodes.Count
End Function
'---------------------------------------------------------------------------------------
' Procedure : Remove
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Removes a node (complete branch) from the tree for a given node key
'---------------------------------------------------------------------------------------
Public Sub Remove(sKey As String)
Dim myNode As clsTreeNode
Set myNode = pTreeNode(sKey)
If Not myNode Is Nothing Then pRemove myNode.UniqueKey
Set myNode = Nothing
End Sub
'---------------------------------------------------------------------------------------
' Procedure : Clear
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Empties the tree
'---------------------------------------------------------------------------------------
Public Sub Clear()
Dim myNode As clsTreeNode
Do While m_cNodes.Count > 0
For Each myNode In m_cNodes
If myNode.IsTopLevelNode Then
pRemove myNode.UniqueKey
Exit For
End If
Next
Loop
Set myNode = Nothing
End Sub
'---------------------------------------------------------------------------------------
' Procedure : DrawTree
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Returns an ASCII representation of a (branch of the) tree
'---------------------------------------------------------------------------------------
Public Function DrawTree(Optional sKey As String, Optional iStartIndentLevel As Integer = 0) As String
Dim myNode As clsTreeNode
Dim sTree As String
If Len(sKey) = 0 Then
For Each myNode In m_cNodes
If myNode.IsTopLevelNode Then
sTree = myNode.DrawTree(iStartIndentLevel)
If Len(DrawTree) = 0 Then
DrawTree = sTree
Else
DrawTree = DrawTree & vbCrLf & sTree
End If
End If
Next
Else
Set myNode = pTreeNode(sKey)
If Not myNode Is Nothing Then
DrawTree = myNode.DrawTree(iStartIndentLevel)
End If
End If
End Function
'---------------------------------------------------------------------------------------
' Procedure : NewEnum
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : To iterate through all nodes using a For..Each loop
'---------------------------------------------------------------------------------------
Public Property Get NewEnum() As IUnknown
Set NewEnum = m_cNodes.[_NewEnum]
End Property
'---------------------------------------------------------------------------------------
' Procedure : pTreeNode
' DateTime : 25-10-2006
' Author : ArnoutV
' Purpose : Returns either the treenode or nothing for a given key
'---------------------------------------------------------------------------------------
Private Function pTreeNode(sKey As String) As clsTreeNode
Dim sUniqueKey As String
On Error GoTo pTreeNode_Error
sUniqueKey = m_cKeys(sKey)
Set pTreeNode = m_cNodes(sUniqueKey)
Exit Function
pTreeNode_Error:
Set pTreeNode = Nothing
End Function
'---------------------------------------------------------------------------------------
' Procedure : pRemove
' DateTime : 30-10-2006
' Author : ArnoutV
' Purpose : Internal removal routine based on unique key
'---------------------------------------------------------------------------------------
Private Sub pRemove(sUniqueKey As String)
Dim myNode As clsTreeNode
Dim cChildNode As clsTreeNode
Dim cParentNode As clsTreeNode
Set myNode = m_cNodes(sUniqueKey)
If myNode.HasChildren Then
For Each cChildNode In myNode.Children
pRemove cChildNode.UniqueKey
Next
End If
Set cParentNode = myNode.Parent
If Not cParentNode Is Nothing Then cParentNode.RemoveChild myNode.Key
If Len(myNode.Key) > 0 Then m_cKeys.Remove myNode.Key
m_cNodes.Remove sUniqueKey
Set myNode = Nothing
End Sub
Private Sub Class_Initialize()
Set m_cNodes = New Collection
Set m_cKeys = New Collection
m_lKeyCnt = 0
End Sub
Private Sub Class_Terminate()
Clear
Set m_cNodes = Nothing
Set m_cKeys = Nothing
End Sub
The TreeNode class
Code:
'---------------------------------------------------------------------------------------
' Module : clsTreeNode
' DateTime : 25-10-2006
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Option Explicit
Private m_cParent As clsTreeNode
Private m_cChildNodes As Collection
Private m_sUniqueKey As String
Private m_sKey As String
Private m_sText As String
Private m_sTag As String
Private m_bHidden As Boolean
Public Property Let UniqueKey(ByVal sValue As String)
m_sUniqueKey = sValue
End Property
Public Property Get UniqueKey() As String
UniqueKey = m_sUniqueKey
End Property
Public Property Let Key(ByVal sValue As String)
m_sKey = sValue
End Property
Public Property Get Key() As String
Key = m_sKey
End Property
Public Property Let Text(ByVal sValue As String)
m_sText = sValue
End Property
Public Property Get Text() As String
Text = m_sText
End Property
Public Property Let Hidden(ByVal bValue As Boolean)
m_bHidden = bValue
End Property
Public Property Get Hidden() As Boolean
Hidden = m_bHidden
End Property
Public Property Let Tag(ByVal sValue As String)
m_sTag = sValue
End Property
Public Property Get Tag() As String
Tag = m_sTag
End Property
Public Property Set Parent(cValue As clsTreeNode)
Set m_cParent = Nothing
Set m_cParent = cValue
End Property
Public Property Get Parent() As clsTreeNode
Set Parent = m_cParent
End Property
Public Sub AddChild(cNode As clsTreeNode)
If Len(cNode.Key) Then
m_cChildNodes.Add cNode, cNode.Key
Else
m_cChildNodes.Add cNode
End If
End Sub
Public Sub RemoveChild(sKey As String)
On Error Resume Next
If Len(sKey) > 0 Then m_cChildNodes.Remove sKey
End Sub
Public Function Child(sKey As String) As clsTreeNode
Set Child = pTreeNode(sKey)
End Function
Public Function ChildIndex(ByVal lIndex As Long) As clsTreeNode
If lIndex > 0 And lIndex <= m_cChildNodes.Count Then
Set ChildIndex = m_cChildNodes(lIndex)
End If
End Function
Public Function IsTopLevelNode() As Boolean
IsTopLevelNode = (m_cParent Is Nothing)
End Function
Public Function IndentLevel() As Long
Dim cParent As clsTreeNode
Set cParent = m_cParent
Do Until cParent Is Nothing
IndentLevel = IndentLevel + 1
Set cParent = cParent.Parent
Loop
Set cParent = Nothing
End Function
Public Function TextPath(Optional sSeparator As String = vbTab) As String
Dim cParent As clsTreeNode
TextPath = m_sText
Set cParent = m_cParent
Do Until cParent Is Nothing
TextPath = cParent.Text & sSeparator & TextPath
Set cParent = cParent.Parent
If Not cParent Is Nothing Then
If cParent.Hidden Then Set cParent = Nothing
End If
Loop
Set cParent = Nothing
End Function
Public Function KeyPath(Optional sSeparator As String = vbTab) As String
Dim cParent As clsTreeNode
Dim sKey As String
sKey = m_sKey
If sKey = "" Then sKey = m_sText
KeyPath = sKey
Set cParent = m_cParent
Do Until cParent Is Nothing
sKey = cParent.Key
If Len(sKey) = 0 Then sKey = cParent.Text
KeyPath = sKey & sSeparator & KeyPath
Set cParent = cParent.Parent
If Not cParent Is Nothing Then
If cParent.Hidden Then Set cParent = Nothing
End If
Loop
Set cParent = Nothing
End Function
Public Function HasChildren() As Boolean
HasChildren = m_cChildNodes.Count > 0
End Function
Public Function NofChildren() As Long
NofChildren = m_cChildNodes.Count
End Function
Public Function Children() As Collection
Set Children = m_cChildNodes
End Function
Public Function ChildKeys() As String()
Dim aKeys() As String
Dim cTreeNode As clsTreeNode
Dim lCnt As Long
If m_cChildNodes.Count > 0 Then
ReDim aKeys(m_cChildNodes.Count - 1)
For Each cTreeNode In m_cChildNodes
aKeys(lCnt) = cTreeNode.Key
lCnt = lCnt + 1
Next
End If
ChildKeys = aKeys
End Function
Public Function DrawTree(Optional ByVal iIndentLevel As Long = 0) As String
Dim cChildNode As clsTreeNode
If iIndentLevel > 0 Then DrawTree = String(iIndentLevel, vbTab)
DrawTree = DrawTree & m_sText
If m_cChildNodes.Count > 0 Then
For Each cChildNode In m_cChildNodes
If Not cChildNode.Hidden Then
DrawTree = DrawTree & vbCrLf & cChildNode.DrawTree(iIndentLevel + 1)
End If
Next cChildNode
End If
End Function
Public Property Get NewEnum() As IUnknown
'this property allows you to enumerate
'this collection with the For...Each syntax
Set NewEnum = m_cChildNodes.[_NewEnum]
End Property
'---------------------------------------------------------------------------------------
' Procedure : pTreeNode
' DateTime : 25-10-2006
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Private Function pTreeNode(sKey As String) As clsTreeNode
On Error GoTo pTreeNode_Error
Set pTreeNode = m_cChildNodes(sKey)
Exit Function
pTreeNode_Error:
Set pTreeNode = Nothing
End Function
Private Sub Class_Initialize()
Set m_cChildNodes = New Collection
Set m_cParent = Nothing
End Sub
Private Sub Class_Terminate()
Set m_cChildNodes = Nothing
Set m_cParent = Nothing
End Sub
-
Jan 16th, 2022, 10:00 AM
#9
Re: Nested Collection Iterations
I know you don't like me bringing up VB.Net in your threads but for the purposes of this specific topic, I cannot avoid it since For...Each works the same way in both VB6 and VB.Net. However, enumerators are exposed in .Net but not in VB6 so I cannot demonstrate what For...Each actually does using VB6 code.
When the compiler encounters a For...Each like this:-
Code:
Dim myArray = {1, 2, 3, 4, 5}
For Each i In myArray
Debug.WriteLine(i)
Next
It turns it into this:-
Code:
Dim myArray = {1, 2, 3, 4, 5}
'Creates an enumerator object. IEnumerator is the .Net equivalent
'of VB6's IEnumVARIANT interface
Dim enumerator As IEnumerator = myArray.GetEnumerator
'Loop through each item using the IEnumerator
'interface
Do While enumerator.MoveNext
Debug.WriteLine(enumerator.Current)
Loop
You can even create multiple enumerator objects to iterate the same list and they can all be in different positions. Example:-
Code:
Dim myArray = {1, 2, 3, 4, 5}
Dim enumerator = myArray.GetEnumerator()
Dim enumerator2 = myArray.GetEnumerator
'Skip two items on the second enumerator
enumerator2.MoveNext()
enumerator2.MoveNext()
Debug.WriteLine("First enumerator:")
Do While enumerator.MoveNext
Debug.WriteLine(enumerator.Current)
Loop
Debug.WriteLine("Second enumerator:")
Do While enumerator2.MoveNext
Debug.WriteLine(enumerator2.Current)
Loop
Output:-
Code:
First enumerator:
1
2
3
4
5
Second enumerator:
3
4
5
As you can see from the above, both enumerators work independently of each other.
Again, I apologize for annoying you yet again with more .Net stuff but I could not demonstrate the concept using VB6 since this is all hidden there. But the concept is exactly the same. For...Each works the exact same way in both languages with some nuanced differences that are not relevant to the overall concept.
-
Jan 16th, 2022, 10:20 AM
#10
Re: Nested Collection Iterations
Niya, VB6 doesn't use IEnumVariant for iterating through arrays it just uses index.
-
Jan 16th, 2022, 11:05 AM
#11
Re: Nested Collection Iterations
Originally Posted by The trick
Niya, VB6 doesn't use IEnumVariant for iterating through arrays it just uses index.
Hi Trick. I assume you're talking about arrays of intrinsic variables, excluding Variants (that is, String, Byte, Boolean, Integer, Long, Single, Double, Currency, Date). Yeah, we've got no way to truly "iterate" those without an explicit For index = a To b loop (or wrapping them in objects).
However, we can iterate a Variant loop. And, nesting seems to work just fine:
Form1:
Code:
Option Explicit
Private Sub Form_Load()
Dim va() As Variant
ReDim va(4)
va(0) = 100
va(1) = 101
va(2) = 102
va(3) = 103
va(4) = 104
Dim v As Variant
For Each v In va
Debug.Print v
NestTest va
Next
End Sub
Sub NestTest(va() As Variant)
Dim v As Variant
For Each v In va
Debug.Print " Nested: "; v
Next
End Sub
Output:
Code:
100
Nested: 100
Nested: 101
Nested: 102
Nested: 103
Nested: 104
101
Nested: 100
Nested: 101
Nested: 102
Nested: 103
Nested: 104
102
Nested: 100
Nested: 101
Nested: 102
Nested: 103
Nested: 104
103
Nested: 100
Nested: 101
Nested: 102
Nested: 103
Nested: 104
104
Nested: 100
Nested: 101
Nested: 102
Nested: 103
Nested: 104
So, I assume these Variant array iteration loops are using IEnumVariant.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 11:55 AM
#12
Re: Nested Collection Iterations
Elroy, i meant what you are talking about:
Code:
Dim v As Variant
For Each v In Array(1, 2, 3, 4, 5, 6)
Debug.Print v
Next
This for-each loop doesn't use IEnumVariant but a hidden index variable.
-
Jan 16th, 2022, 12:04 PM
#13
Re: Nested Collection Iterations
Originally Posted by The trick
Elroy, i meant what you are talking about :
Code:
Dim v As Variant
For Each v In Array(1, 2, 3, 4, 5, 6)
Debug.Print v
Next
This for-each loop doesn't use IEnumVariant but a hidden index variable.
Hmmm, ok. Good to know.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 12:16 PM
#14
Re: Nested Collection Iterations
Ok, I've got another related question.
When iterating a Collection, we've established that it uses an IEnumVariant mechanism to keep track of iterations. However, we've still got several ways to get out of these iteration loops (Exit For, Exit Do, Exit Sub/Function, GoTo).
And, I'm assuming that, in all those cases, the loop somehow cleans up the IEnumVariant mechanism? Correct? It's a bit curious to me how it does that, as something like a GoTo is a pretty raw exit.
As an analogy, I'm comfortable with VB6 cleaning up object variables (and arrays, and strings) when they fall out of scope. And, VB6 sort of "cheats" this by not having variables more specific than procedures, so that's all easier to keep track of. However, the IEnumVariant mechanism is more specific.
(Also, I guess the same question applies to a variant array enumeration. Even if it doesn't use IEnumVariant, it's still got to clean up its internal index variable when we exit the loop.)
Also, I'm now curious about what happens if/when we GoTo into the middle of one of these loops. I'll test and see.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 12:34 PM
#15
Re: Nested Collection Iterations
When you use Exit For statement it immediately cleans-up the enumerator reference. When you use GoTo statement the enumerator is released when the function exits. An index variable isn't freed because it's just an integer value.
-
Jan 16th, 2022, 12:35 PM
#16
Re: Nested Collection Iterations
I figured it out.
These IEnumVariant variables and the Variant Array index variables are also procedure scoped variables. As such, they get cleaned up when the procedure exits (just like all other procedure scoped variables). So, on Exit For, Exit Do, & GoTo, they don't get cleaned up. But on Exit Sub & Exit Function, they do get cleaned up.
EDIT: I suppose I should say "procedure lifetime" rather than "procedure scoped", so that any Static variables aren't confused. Although, these IEnumVariant and Variant Array index variables almost certainly aren't static, so scope and lifetime is the same.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 12:37 PM
#17
Re: Nested Collection Iterations
Originally Posted by Elroy
I figured it out.
These IEnumVariant variables and the Variant Array index variables are also procedure scoped variables. As such, they get cleaned up when the procedure exits (just like all other procedure scoped variables). So, on Exit For, Exit Do, & GoTo, they don't get cleaned up. But on Exit Sub & Exit Function, they do get cleaned up.
No. When you use Exit For or an loop is finished normally the enumerator is freed immediately.
-
Jan 16th, 2022, 12:38 PM
#18
Re: Nested Collection Iterations
Originally Posted by The trick
When you use Exit For statement it immediately cleans-up the enumerator reference. When you use GoTo statement the enumerator is released when the function exits. An index variable isn't freed because it's just an integer value.
Ahhh, I can test that.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 12:42 PM
#19
Re: Nested Collection Iterations
Ahh, Trick, you are correct as usual.
Code:
Option Explicit
Private Sub Form_Load()
Dim c As New Collection
c.Add 100
c.Add 101
c.Add 102
c.Add 103
c.Add 104
Dim v As Variant
For Each v In c
Debug.Print v
If v = 102 Then Exit For
label1:
Next
If v = 104 Then Exit Sub
GoTo label1
End Sub
Output:
Termination:
... on the "Next" statement.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 16th, 2022, 12:44 PM
#20
Re: Nested Collection Iterations
Code:
For Each o In z
Exit For
in_loop:
Next
exit_loop:
GoTo in_loop
Code:
For Each o In z
GoTo exit_loop
in_loop:
Next
End
exit_loop:
GoTo in_loop
-
Jan 16th, 2022, 05:55 PM
#21
Re: Nested Collection Iterations
Originally Posted by The trick
Niya, VB6 doesn't use IEnumVariant for iterating through arrays it just uses index.
I'm aware there are differences. I was focused on this:-
For each" cycle for objects is based on the IEnumVariant interface. So when you initiate a loop the runtime requests for an IEnumVariant enumerator object (through DISPID_NEWENUM request). This object usually is a different object which has its own state like the current item etc.
I wasn't too focused on the details. But good info nonetheless.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|