Post

VB10 vs VB6: Array Lower Bounds

This is part of series of posts categorized under VB10 vs VB6.

“Arrays may not have a lower bound other than zero.”

This, as it turns out, is absolutely true; however, with a twist. Although VB10 does not allow the “native” array type (the one defined by the language), there are a ton of ways that this can be handled. I would also argue that the multitude of ways that are available would also provide a solution that better suites the needs for circumstances where having a different lower bound is desired.

Let’s see how you could accomplish similar functionality without delving into the .NET Framework. The most direct solution is to handle the lower bound yourself by determining the offset from 0 and access the array accordingly.

1
2
3
4
Dim lbound As Integer = 10 
Dim ubound As Integer = 20 
Dim a(ubound - lbound) As Integer
a(10 - lbound) = value 

So you could easily handle this by utilizing some simple math. Let’s say, however, that you’d like to have it programatically similar to VB6. You could create a class that abstracts this math and provides a very similar experience to VB6.

1
2
Dim a As New VbIntegerArray(lbound, ubound)
a(10) = value 

The code for the VbIntegerArray is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Public Class VbIntegerArray

  Private m_lbound As Integer
  Private m_int() As Integer

  Public Sub New(ByVal lowerBound As Integer, ByVal upperBound As Integer)
    Me.ReDim(lowerBound, upperBound)
  End Sub

  Public Sub [ReDim](ByVal lowerBound As Integer, ByVal upperBound As Integer)
    m_lbound = lowerBound
    ReDim m_int(upperBound - lowerBound + 1)
  End Sub

  Default Public Property Item(ByVal index As Integer) As Integer
    Get
      Return m_int(index - m_lbound)
    End Get
    Set(ByVal Value As Integer)
      m_int(index - m_lbound) = Value
    End Set
  End Property
 
End Class

Not too difficult. Note, this code is based off of a blog entry by Phil Weber. I made a few minor changes to, so feel free to use this or his depending on your needs. Using this method requires that you create a separate class for each variable type you want to have an “array” with a different lower bounds than 0. Another approach, as mentioned toward the end of Phil’s blog entry is the possibility of using Generics. I’ve re-wired the above class to create a generic version. The internal implementation is not a ‘native’ language array, but instead is leveraging the Generic List object. Because of this, I am having to pre-populate the “array” with items so that the indexer works as expected. Furthermore, because it is a generic type, I’m populating each entry with Nothing (NULL). Outside of that, everything is basically similar to the direct implementation.

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
Public Class VbArrayGeneric(Of T)

  Private m_lbound As Integer
  Private m_array As List(Of T)

  Public Sub New(ByVal lowerBound As Integer, ByVal upperBound As Integer)
    Me.ReDim(lowerBound, upperBound)
  End Sub

  Public Sub [ReDim](ByVal lowerBound As Integer, ByVal upperBound As Integer)
    m_lbound = lowerBound
    m_array.Clear()
    For index As Integer = 0 To upperBound - lowerBound
      m_array.Add(Nothing)
    Next
  End Sub

  Default Public Property Item(ByVal index As Integer) As T
    Get
      Return m_array(index - m_lbound)
    End Get
    Set(ByVal Value As T)
      m_array(index - m_lbound) = Value
    End Set
  End Property

End Class

To utilize the above code, you can do the following:

1
2
3
4
5
6
7
8
9
Dim a As New VbArrayGeneric(Of Integer)(10, 20)

For index As Integer = 10 To 20
  a(index) = index
Next

For index As Integer = 10 To 20
  Console.WriteLine(a(index))
Next

In addition to the ways described, the Generic version of the Dictionary class might also be leveraged to provide similar capabilities. By using a dictionary, you would no longer be bound (no pun intended) to a lower and upper bound since each entry has a unique key and can be of any value. If interested in seeing this approach, please let me know.

Verdict

This one’s hard to provide a clear verdict. On the one hand, it’s clear that the ‘native’ language array does not support arrays with a lower bound other than 0. On the other, there are a plethora of ways to implement “arrays” available in VB10. Because of this, I’m going to call this one a wash. (Note: I may come back and give this one to VB6 depending on how the rest of the list goes; only because of the way that the entry was stated, VB10 does not do exactly what it states.)

Update(s)

Bill McCarthy (MVP) writes in : “I’d add IEnumerable/IEnumerable(Of T) support to the classes passing it straight through to the array’s GetEnumerator. And this is actually where it gets interesting. If I recall correctly For Each with arrays in .NET is optimized; you’d probably lose a little bit with the custom class, but as long as it was IEnumerable(Of T) as opposed to the non-generic version there shouldn’t be any boxing overhead. That said, I seem to recall (but don’t quote me on this as it is a LONG time ago), that VB6 had performance problems with For Each (pCode versus native may have changed the outcome too), as I think it went all variant gooey stuff ;) Anyway, real world implementation in .NET, include IEnumerable(Of T).

This post is licensed under CC BY 4.0 by the author.