If you’re anything like me and ever had to code anything in Visual Basic for Applications, you must have felt the need for a proper API with some very basic common ADTs. The most basic of them being, in my opinion, the dynamic array (Vector, ArrayList, List and Collection are often used more or rather less synonymous). So what would it feel like to be able to write this and have it work?

Dim primitiveVector As clsVector
Set primitiveVector = New clsVector
Dim myInt As Integer
myInt = 3
 
primitiveVector.AddItem myInt

There are of course other people who have made such a thing, and there’s the VBA Collection, but none of them quite fit what I wanted. I wanted a Vector that had random access, was able to handle LIFO and FIFO (and thus act as stack and queue), addition and insertion and deletion, could check for item existence, and had dynamic resizing. So I went and coded my own. I did this while working at Promino AG and thus the code is technically theirs, so thanks to Paul Moser for the nod for publishing this under the GNU Lesser General Public License.

floppy VBA Vector ClassesYou can download both classes (two? more below), together with a tiny trivial testing framework, as Access 2002-2003 .mdb.

This here is the vector class for Variants. It goes into a new class module, I called mine “clsVector”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
Option Compare Database
Option Explicit
 
' Copyright 2007, 2008 by Promino AG
' Author: Guido Gloor
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU Lesser General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU Lesser General Public License for more details.
'
' You should have received a copy of the GNU Lesser General Public License
' along with this program.  If not, see <http://www.gnu.org/licenses/>.

Private itemCount As Integer
Private itemBufferSize As Integer
Private itemBuffer() As Variant
 
Private Sub Class_Initialize()
    itemCount = 0
    itemBufferSize = 100
    NewDimensions
End Sub
 
Private Sub NewDimensions()
    ReDim Preserve itemBuffer(itemBufferSize) As Variant
End Sub
 
Private Sub CheckDimensions()
    If itemCount > itemBufferSize - 2 Then
        itemBufferSize = itemBufferSize * 2
        NewDimensions
    End If
End Sub
 
Public Sub ShrinkDimensions()
    itemCount = itemBufferSize + 10
    NewDimensions
End Sub
 
Public Function GetSize() As Integer
    GetSize = itemCount
End Function
 
Public Sub AddItem(item As Variant)
    CheckDimensions
    itemBuffer(itemCount) = item
    itemCount = itemCount + 1
End Sub
 
Public Function GetItem(index As Integer) As Variant
    GetItem = itemBuffer(index)
End Function
 
Public Function PopItem() As Variant
    PopItem = itemBuffer(itemCount - 1)
    DeleteItem itemCount - 1
End Function
 
Public Function GetNextQueueItem() As Variant
    GetNextQueueItem = itemBuffer(0)
    DeleteItem 0
End Function
 
Public Function ContainsItem(item As Variant) As Boolean
    Dim i As Integer
    ContainsItem = False
 
    For i = 0 To itemCount - 1
        If itemBuffer(i) = item Then ContainsItem = True
    Next i
End Function
 
Public Sub InsertItem(index As Integer, item As Variant)
    Dim i As Integer
 
    CheckDimensions
    For i = itemCount - 1 To index Step -1
        itemBuffer(i + 1) = itemBuffer(i)
    Next i
    itemBuffer(index) = item
    itemCount = itemCount + 1
End Sub
 
Public Sub DeleteItem(index As Integer)
    Dim i As Integer
 
    For i = index + 1 To itemCount - 1
        itemBuffer(i - 1) = itemBuffer(i)
    Next i
    itemCount = itemCount - 1
End Sub
 
Public Function IsEmpty() As Boolean
    IsEmpty = itemCount <= 0
End Function

Now, it would be nice if we would be done. But, we’re not done yet, obviously, after all there’s plenty more code below this break. The reason for that is simple: In VBA, a Variant is not an Object, and an Object is not a Variant, consequently functions that take Objects don’t take Variants and vice versa (although you can technically store an Object in a Variant, this will lead to problems). Objects also happen to have “Set” mandatory in places where it isn’t allowed for Variants.

What this means is that there is no way to have the same Vector class for both your custom ADTs and the primitive data types. So basically, we have another class that has exactly the same functions and exactly the same algorithms, but takes Objects instead of Variants. I called mine “clsObjectVector”. Here is the source for the class module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Option Compare Database
Option Explicit
 
' Copyright 2007, 2008 by Promino AG
' Author: Guido Gloor
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU Lesser General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU Lesser General Public License for more details.
'
' You should have received a copy of the GNU Lesser General Public License
' along with this program.  If not, see <http://www.gnu.org/licenses/>.

Private itemCount As Integer
Private itemBufferSize As Integer
Private itemBuffer() As Object
 
Private Sub Class_Initialize()
    itemCount = 0
    itemBufferSize = 100
    NewDimensions
End Sub
 
Private Sub NewDimensions()
    ReDim Preserve itemBuffer(itemBufferSize) As Object
End Sub
 
Private Sub CheckDimensions()
    If itemCount > itemBufferSize - 2 Then
        itemBufferSize = itemBufferSize * 2
        NewDimensions
    End If
End Sub
 
Public Sub ShrinkDimensions()
    itemCount = itemBufferSize + 10
    NewDimensions
End Sub
 
Public Function GetSize() As Integer
    GetSize = itemCount
End Function
 
Public Sub AddItem(item As Object)
    CheckDimensions
    Set itemBuffer(itemCount) = item
    itemCount = itemCount + 1
End Sub
 
Public Function GetItem(index As Integer) As Object
    Set GetItem = itemBuffer(index)
End Function
 
Public Function PopItem() As Object
    Set PopItem = itemBuffer(itemCount - 1)
    DeleteItem itemCount - 1
End Function
 
Public Function GetNextQueueItem() As Object
    Set GetNextQueueItem = itemBuffer(0)
    DeleteItem 0
End Function
 
Public Function ContainsItem(item As Object) As Boolean
    ' The used ADTs need to have an Equals function for this to work
    Dim i As Integer
    ContainsItem = False
 
    For i = 0 To itemCount - 1
        If itemBuffer(i).Equals(item) Then ContainsItem = True
    Next i
End Function
 
Public Sub InsertItem(index As Integer, item As Object)
    Dim i As Integer
 
    CheckDimensions
    For i = itemCount - 1 To index Step -1
        Set itemBuffer(i + 1) = itemBuffer(i)
    Next i
    Set itemBuffer(index) = item
    itemCount = itemCount + 1
End Sub
 
Public Sub DeleteItem(index As Integer)
    Dim i As Integer
 
    For i = index + 1 To itemCount - 1
        Set itemBuffer(i - 1) = itemBuffer(i)
    Next i
    itemCount = itemCount - 1
End Sub
 
Public Function IsEmpty() As Boolean
    IsEmpty = itemCount <= 0
End Function

This is it, have fun :-) As much as you can have if you’re forced to work with VBA, that is.

Oh, and if you can use it – comments are appreciated :-P