ArrayedList Class

It’s a bit disappointing that the VBA library contains only one collection class: Collection. Obviously, that one’s there because of its use to hold application objects (Worksheets, Controls, etc). However, it’s common to need other types of collection (with a small ‘c’): various sorts of lists, for example.

One that I needed recently was a list where I could add to the end, and iterate through the entire set. Since I didn’t need to insert/delete within the list, a Linked List was unnecessary. So I went for a simple wrapping of an array: ArrayedList. (Okay, I could probably find one out there on the ‘net, but it’s more fun to write your own). The public features are:

Public Sub Add(x As Variant)

Property Get Count() As Long

Property Get Nth(i As Long) As Variant

The wrapped array is re-sized when I Add beyond the current upper bound. The scale of the re-sizing is determined by a ‘chunk’ constant. Here’s the full code:

Const al_chunk As Long = 10
Private al_arr() As Variant
Private al_lastused As Long
Private al_max As Long

Private Sub Class_Initialize()
    ReDim al_arr(1 To al_chunk)
    al_max = UBound(al_arr)
End Sub

Public Sub Add(x As Variant)
    If al_lastused = al_max Then
        ReDim Preserve al_arr(1 To al_max + al_chunk)
        al_max = UBound(al_arr)
    End If
    al_lastused = al_lastused + 1
    al_arr(al_lastused) = x
End Sub

Property Get Count() As Long
    Count = al_lastused
End Property

Property Get Nth(i As Long) As Variant
    If i <= al_lastused Then
        Nth = al_arr(i)
    End If
End Property

Note the ReDim Preserve in the Add method. Obviously there’s some performance impact for huge numbers of elements.

Note also that in the Nth property, there’s a protecting conditional (i <= al_lastused). This means that it can be called with an out-of-range index, in which case the default empty value will be returned, and the caller might have to check for this. There’s a difference here from having the condition as a pre-condition (see earlier postings). A pre-condition would mean the the caller would have to ensure a valid index, perhaps by an explicit check against the Count property. The choice depends on whether we think that returning empty values is sensible or not for this class.

Talking about assertions (sound of saddle being put on hobby-horse), here’s a class invariant:

Sub Invariant()
    If Not (al_chunk > 0 And _
            LBound(al_arr) = 1 And _
            UBound(al_arr) >= al_chunk And _
            al_max = UBound(al_arr) And _
            al_lastused <= al_max) Then
       Err.Raise vbObjectError + 513,
            "UsingClasses.SmartArray", "Invariant failed"
    End If
End Sub

Rather than having it as a Boolean function, it’s a sub that raises an error. This means that the testing code that calls Invariant will stop with an error, rather than logging the failure and continuing. Given that an invariant failure indicates something pretty fundamentally wrong, that might be the better approach.


0 Responses to “ArrayedList Class”

  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

July 2009
« Jun   Aug »

%d bloggers like this: