Passing And Returning Arrays With Functions

         In VBA, you can pass arrays to procedures (Subs, Functions, and Properties), and Functions and Properties (Property Get only) can return arrays as their result. (Note that returning an array as the result of a function or property was added in Office 2000 -- functions in Office 97 cannot return arrays.)  However, you must be aware of the limitations in passing arrays. This page assumes you are familiar with the fundamentals of VBA arrays and the difference between a static and a dynamic array.

As a general coding practice, I always use dynamic arrays and use ReDim to size the array to the necessary dimensions. This makes code more flexible and re-usable. It is quite rare that I will be dealing with a fixed number of entities or objects whose number is known at design time. Using dynamic arrays allows the software to size itself for the task at hand. In fact, I can think of no situation in which a static array would be superior to a dynamic array.

The procedures and code on this page use the array support functions described on the Functions For VBA Arrays page. If you are going to use the example code on this page in your VBA code, you should copy the functions on that page into a module in your VBA project, or get the code module here and import this module into your VBA project. We will use the same terminology as described on the Functions For VBA Arrays page.

Passing Arrays To Procedures
A procedure (a Sub, Function or Property) can accept an array as an input parameter.  The first thing to understand is that arrays are always passed by reference  (
ByRef). You will receive a compiler error if you attempt to pass an array ByVal. (See the Online VBA Help for the topic Sub Statement for information about ByRef and ByVal.) This means that any modification that the called procedure does to the array parameter is done on the actual array declared in the calling procedure. This is illustrated in the following code:

Sub AAATest()
    Dim StaticArray(1 To 3) As Long
    Dim N As Long
    Arr(1) = 1
    Arr(2) = 2
    Arr(3) = 3
    PopulatePassedArray Arr:=StaticArray
    For N = LBound(StaticArray) To UBound(StaticArray)
        Debug.Print StaticArray(N)
    Next N
End Sub

Sub PopulatePassedArray(ByRef Arr() As Long)
    ''''''''''''''''''''''''''''''''''''
    ' PopulatePassedArray
    ' This puts some values in Arr.
    ''''''''''''''''''''''''''''''''''''
    Dim N As Long
    For N = LBound(Arr) To UBound(Arr)
        Arr(N) = N * 10
    Next N
End Sub

In this code, the array StaticArray is passed to the PopulatePassedArray procedure. The ByRef keyword is not required in the parameter list of the procedure PopulatePassedArray (ByRef is the default in VB/VBA), but I tend include ByRef in parameter declarations if I am going to modify that variable. It serves as a reminder that a variable in the calling procedure is going to be modified by the called procedure. I don't include the ByRef keyword for variables whose content I am not going to modify.  You may safely omit ByRef if you prefer. Since the array StaticArray is passed by reference, the variable StaticArray in the calling procedure AAATest is modified by the code in the called procedure PopulatePassedArray .

In a real-word, commercial-quality application, you would first test to ensure that the array
Arr has actually been allocated and the the array is single-dimensional.  You can use the IsArrayAllocated and NumberOfArrayDimensions functions, described on the Functions For VBA Arrays page, to test these conditions.  For example, you would write the called procedure as:

Sub PopulatePassedArray(ByRef Arr() As Long)
    ''''''''''''''''''''''''''''''''''''
    ' PopulatePassedArray
    ' This puts some values in Arr.
    ''''''''''''''''''''''''''''''''''''
    Dim N As Long
    If IsArrayAllocated(Arr:=Arr) = True Then
        If NumberOfArrayDimensions(Arr:=Arr) = 1 Then
            For N = LBound(Arr) To UBound(Arr)
                Arr(N) = N * 10
            Next N
        Else
            Debug.Print "Array is has multiple dimensions."
           '''''''''''''''''''''''''''''''''''''''
           ' Take whatever action is necessary
           ' for a multi-dimensional array,
           ' such as resizing the array.
           '''''''''''''''''''''''''''''''''''''''
        End If
    Else
        Debug.Print "Array Not Allocated."
        '''''''''''''''''''''''''''''''''''''''
        ' Take whatever action necessary with
        ' an unallocated array, such as ReDim
        ' the array.
        '''''''''''''''''''''''''''''''''''''''
   End If
End Sub

You may have noticed that the static array StaticArray in AAATest has the same data type (Long) as the array Arr declared in the parameter list to PopulatePassedArray . This is no coincidence.  The rule here is that the data type of the array declared in the calling procedure must match the data type declared in the called procedure's parameter list.   While you can declare a simple parameter As Variant to accept a parameter to be of any data type, this does not work for arrays. It is a very common misconception that declaring the function parameter As Variant() will allow you to accept an array of any type. This is flat wrong.  You cannot declare the array in the parameter list of the called procedure As Variant() to accept any data type array. The data types must explicitly match; otherwise, you'll get a "Type Mismatch: Array or user-defined type expected." error when you compile and run the code. If you declare the function parameter As Variant() then you must pass an array of Variants.

Moreover, if a function parameter is declared as an array, you cannot pass a single Variant as that function parameter, even if the Variant contains an array of the proper data type. For example, the following code will not compile.

Sub AAATest()
    Dim V As Variant
    Dim L(1 To 3) As Long
    L(1) = 100
    L(2) = 200
    L(3) = 300
    V = L
    BBB L '<<< Works because L is a Long Array.
    BBB V '<<< Compiler error here. V itself is not an array, as expected by BBB.
End Sub

Sub BBB(Arr() As Long)
    Debug.Print Arr(LBound(Arr))
End Sub

Since an array passed from the calling procedure to the called procedure is passed by reference, the called procedure may use the ReDim statement to change the size of the passed array and/or number of dimensions (the passed array must declared as a dynamic array in the calling procedure, but it need not be allocated). This is perfectly legal and indeed quite useful.  For example, in the procedures below, the array DynArray is declared as a dynamic array in AAATest, and it is resized as many times as needed to store the results in the PopulateArrayWithCellValuesGreaterThan10 procedure.

Sub AAATest()
    Dim DynArray() As Double ' Note that this array is not sized
                             ' in the Dim statement. We'll use ReDim
                             ' in the called procedure to change the size.
    Dim N As Long
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' Call PopulateArrayWithCellValuesGreaterThan10 to resize
    ' the array and populate its elements with values.
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    PopulateArrayWithCellValuesGreaterThan10 Arr:=DynArray, TestRng:=Range("A1:A10")
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' Ensure that PopulateArrayWithCellValuesGreaterThan10
    ' allocated the array.
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''  
    If IsArrayAllocated(Arr:=DynArray) = True Then
        For N = LBound(DynArray) To UBound(DynArray)
            Debug.Print DynArray(N)
        Next N
    End If
End Sub

Sub PopulateArrayWithCellValuesGreaterThan10(ByRef Arr() As Double, TestRng As Range)
    ''''''''''''''''''''''''''''''''''''''''''''''''''
    ' PopulateArrayWithCellValuesGreaterThan10
    '
    ' This resizes Arr and places in it the values
    ' in the range TestRng that are greater than 10.
    ''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Rng As Range
    Dim Ndx As Long
    ''''''''''''''''''''''''''''''''
    ' Ensure TestRng is not Nothing.
    ''''''''''''''''''''''''''''''''
    If TestRng Is Nothing Then 
        MsgBox "TestRng Is Nothing"
        Exit Sub
    End If
    ''''''''''''''''''''''''''''''''
    ' Loop through the range.
    ''''''''''''''''''''''''''''''''
    For Each Rng In TestRng.Cells
        If IsNumeric(Rng.Value) = True Then 
            If Rng.Value > 10 Then
                Ndx = Ndx + 1
                ReDim Preserve Arr(1 To Ndx)
                Arr(Ndx) = CDbl(Rng.Value)
            End if
        End If
    Next Rng
End Sub

In the PopulateArrayWithCellValuesGreaterThan10 procedure, the array Arr (which is the same array as DynArray in AAATest) is resized using the ReDim Preserve statement each time a cell value greater than 10 is encountered. While this is perfectly legal code, and it illustrates resizing an array parameter, the code is neither safe nor efficient.  The code doesn't test whether the array is dynamic and therefore can be resized. If we were passed a static array, we would get a run-time error 10 ("The array is fixed or temporarily locked.") when calling  ReDim Preserve. Moreover, the code calls the ReDim Preserve statement any number of times, as many times as a cell value exceeds 10.  ReDim Preserve is an expensive operation (especially with large arrays of Strings or Variants) and should be used sparingly.  A much better version of the procedure is shown below.

Sub AAATest()
    Dim DynArray() As Double ' Note that this array is not sized
                             ' in the Dim statement. We'll use ReDim
                             ' to change the size later.
    Dim N As Long
    PopulateArrayWithCellValuesGreaterThan10 Arr:=DynArray, TestRng:=Range("A1:A10")
    If IsArrayAllocated(Arr:=DynArray) = True Then
        For N = LBound(DynArray) To UBound(DynArray)
            Debug.Print DynArray(N)
        Next N
    End If
End Sub

Sub PopulateArrayWithCellValuesGreaterThan10(ByRef Arr() As Double, TestRng As Range)
    ''''''''''''''''''''''''''''''''''''''''''''''''''
    ' PopulateArrayWithCellValuesGreaterThan10
    '
    ' This resizes Arr once to the maximum number
    ' of elements we may use, populates the array
    ' elements, and then uses ReDim Preserve to
    ' resize the array to the number of elements
    ' actually used. This avoids calling Redim
    ' Preserve for each cell in the range.
    '
    ' It calls IsArrayDynamic to ensure that Arr 
    ' is a dynamic array that can be resized. 
    ''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Rng As Range
    Dim Ndx As Long
    ''''''''''''''''''''''''''''''''
    ' Ensure TestRng is not Nothing.
    ''''''''''''''''''''''''''''''''
    If TestRng Is Nothing Then 
        MsgBox "TestRng Is Nothing"
        Exit Sub
    End If 
    ''''''''''''''''''''''''''''''''
    ' Call IsArrayDynamic to ensure
    ' that we have a dynamic array.
    ''''''''''''''''''''''''''''''''   
    If IsArrayDynamic(Arr:=Arr) = True Then
        '''''''''''''''''''''''''''''''''''
        ' ReDim Arr to the number of cells
        ' in TestRng. This is the maximum
        ' possible entries we might use -- 
        ' the number of cells in the TestRng 
        ' range. We don't use Preserve 
        ' with ReDim here because we don't want
        ' to preserve any existing values.
        ' Any values currently in the array 
        ' will be lost. 
        '''''''''''''''''''''''''''''''''''
        ReDim Arr(1 To TestRng.Cells.Count)
        Ndx = 0
        For Each Rng In TestRng.Cells
	    If IsNumeric(Rng.Value) = True Then            
                If Rng.Value > 10 Then
                    Ndx = Ndx + 1
                    Arr(Ndx) = CDbl(Rng.Value)
                End If
            End If
        Next Rng
        '''''''''''''''''''''''''''''''''''
        ' ReDim Preserve to reduce the size 
        ' the array to only as many elements 
        ' as we used.
        '''''''''''''''''''''''''''''''''''
        ReDim Preserve Arr(1 To Ndx)
    Else
        ''''''''''''''''''''''''''''''''''''''''''
        ' Code for the case if Arr is not dynamic.
        ''''''''''''''''''''''''''''''''''''''''''
        Exit Sub
    End If
End Sub

In this code, we first call the function IsArrayDynamic (this function is illustrated on the Functions For VBA Arrays page) to ensure that Arr is an dynamic array that we can resize. If this function returns True, the array is dynamic and we can resize it. If the function returns False, the array is static, and we would probably raise an error or just exit the sub. The procedure then calls ReDim once to size the array to the number of cells in the range (the maximum possible size we'll need for the array), and then calls ReDim Preserve at the end to reduce the size to the actual number of elements actually used. (ReDim Preserve  is usually used to increase the size of an array, but it is equally valid to use it to reduce the size of an array). Note that the first call to ReDim doesn't use the Preserve  keyword. This is because we don't want to preserve any values that might be in the array. Calling ReDim without Preserve resizes the array but destroys its existing contents.

Note that when you declare an array in called procedure's parameter list, you do not (and cannot) include its size, even if it is a static array.  For example, the following code is illegal and will not compile:

Public Sub CalledProcedure (Arr(1 to 3) As Long)

Instead you use code like

Public Sub CalledProcedure (Arr() As Long)

The lack of lower and upper bounds within the parentheses in the parameter declaration of Arr, however, does not mean that the array somehow has been made a dynamic array. If it was declared static in calling function, it remains static when accessed by the called procedure. The "()" characters after the parameter name in the called procedure's parameter list simply indicate that an array, either static or dynamic, is being passed. It is up to the called procedure to determine whether the passed array is static or dynamic, if necessary.  You can use the IsArrayDynamic  function to test this condition.

There is no way to change a static array into a dynamic array. If it is sized in the
Dim statement, it can never be resized.  Its size is fixed, and any attempt to resize the array will cause a compiler error ("Array already dimensioned"). You can, of course, create a new dynamic array and load it with the contents of a static array:

    Dim StaticArray(1 To 3) As Long
    Dim DynArray() As Double
    Dim Ndx As Long
    ' Load StaticArray with some data  
    ReDim DynArray(LBound(StaticArray) To UBound(StaticArray))
    For Ndx = LBound(StaticArray) To UBound(StaticArray)
        DynArray(Ndx) = StaticArray(Ndx)
    Next Ndx

In this case, the data types need not match. They just must be compatible (e,g, both should be numeric types).

You can pass static arrays to procedures, just as you can dynamic arrays. As with dynamic arrays, static arrays are passed by reference.  The only difference is that you cannot resize a static array. For example, the following code passes a static array to a function.

Sub AAATest()
    Dim StaticArray(1 To 3) As Long
    Dim Result As Long
    StaticArray(1) = 10
    StaticArray(2) = 20
    StaticArray(3) = 30
    Result = SumArray(Arr:=StaticArray)
    Debug.Print Result
End Sub

Function SumArray(Arr() As Long) As Long
    '''''''''''''''''''''''''''''''''''''''''''
    ' SumArray
    ' This sums the elements of Arr and returns
    ' the total.
    ''''''''''''''''''''''''''''''''''''''''''' 
    Dim N As Long
    Dim Total As Long
    For N = LBound(Arr) To UBound(Arr)
        Total = Total + Arr(N)
    Next N
    SumArray = Total
End Function

The SumArray function just loops through the array, summing the values, and returns the result.

Because the data type of the array in the calling procedure must match the data type in the array parameter declaration in the called procedure, you may wonder how to call a procedure that can handle various other data types, which may not be known until run-time.  For example, how would
SumArray be written to handle arrays of Integers or Doubles as well as Longs?

To pass an array of any type to a procedure, don't declare the parameter as an array. Instead, declare it as a Variant (not an array of Variants).  A single Variant variable may contain an array.  This is illustrated in the code below.  

Sub AAATest()
    Dim StaticArray(1 To 3) As Double
    Dim Result As Double
    StaticArray(1) = 10
    StaticArray(2) = 20
    StaticArray(3) = 30
    Result = SumArray(Arr:=StaticArray)
    Debug.Print Result
End Sub

Function SumArray(Arr As Variant) As Double
    '''''''''''''''''''''''''''''''''''''''''''
    ' SumArray
    ' This sums the elements of Arr and returns
    ' the total.
    '''''''''''''''''''''''''''''''''''''''''''
    Dim N As Long
    Dim Total As Double
    '''''''''''''''''''''''''
    ' Ensure Arr is an array.
    '''''''''''''''''''''''''
    If IsArray(Arr) = True Then
        ''''''''''''''''''''''''''''''''
        ' Ensure the array is allocated.
        ''''''''''''''''''''''''''''''''
        If IsArrayAllocated(Arr:=Arr) = True Then
            ''''''''''''''''''''''''''''''''
            ' Ensure Arr is one-dimensional.
            ''''''''''''''''''''''''''''''''
            If NumberOfArrayDimensions(Arr:=Arr) = 1 Then
                '''''''''''''''''''''''''''''''''''''
                ' Ensure Arr is a numeric type array.
                '''''''''''''''''''''''''''''''''''''
                If IsNumericDataType(Arr) = True Then
                    For N = LBound(Arr) To UBound(Arr)
                        '''''''''''''''''''''''''''
                        ' Ensure Arr(N) is numeric.
                        '''''''''''''''''''''''''''
                        If IsNumeric(Arr(N)) = True Then
                            Total = Total + Arr(N)
                        End If
                    Next N
                Else
                    Debug.Print "Array is not numeric."
                    ''''''''''''''''''''''''''''''''''
                    ' Code in case Arr is not numeric.
                    ''''''''''''''''''''''''''''''''''
                    Exit Function
                End If
            Else
                Debug.Print "Array is not one-dimensional."
                ''''''''''''''''''''''''''''''''''''''''
                ' Code in case Arr is multi-dimensional.
                ''''''''''''''''''''''''''''''''''''''''
                Exit Function
            End If
         Else
            Debug.Print "Array is not allocated."
             ''''''''''''''''''''''''''''''''''''
             ' Code in case Arr is not allocated.
             ''''''''''''''''''''''''''''''''''''
             Exit Function
         End If
    Else
        Debug.Print "Input is not an array."
        '''''''''''''''''''''''''''''''''''
        ' Code in case Arr is not an array.
        '''''''''''''''''''''''''''''''''''
        Exit Function
    End If
    SumArray = Total
End Function

You'll notice that this version of SumArray has much more error checking that the earlier version. This is because in the first version Arr was declared as an array of Longs. This means that we didn't need to test whether it was an array and we didn't need to test whether its elements were numeric. But in this later verison, Arr is a Variant that can contain anything, so we need more error checking to ensure everything is valid.  With this code, you can pass to an array of any type to  SumArray.



Returning An Array From A Function

Beginning with VBA version 6 (Office 2000 and later), a Function procedure or a Property Get procedure may return an array as its result. (In Office97, the function must store the array in a Variant and return the Variant.) The variable that receives the array result must be a dynamic array and it must have the same data type as the returned array.  You cannot declare the receiving array as an array of Variants to accept an array of any type. This will not work. The receiving array must have the same data type as the returned array or it must be a single Variant (not an array of Variants).

For example, the following function will load an array with numbers from Low to High and return the array as its result. Note that the variable
Arr in AAATest and the return type of LoadNumbers have the same data type (Long).

Sub AAATest()
    Dim Arr() As Long
    Dim N As Long
    Arr = LoadNumbers(Low:=101, High:=110)
    If IsArrayAllocated(Arr:=Arr) = True Then
        For N = LBound(Arr) To UBound(Arr)
           Debug.Print Arr(N)
        Next N
    Else
        ''''''''''''''''''''''''''''''''''''
        ' Code in case Arr is not allocated.
        ''''''''''''''''''''''''''''''''''''
    End If
End Sub

Function LoadNumbers(Low As Long, High As Long) As Long()
    '''''''''''''''''''''''''''''''''''''''
    ' Returns an array of Longs, containing
    ' the numbers from Low to High. The 
    ' number of elements in the returned
    ' array will vary depending on the 
    ' values of Low and High.
    ''''''''''''''''''''''''''''''''''''''''
    
    '''''''''''''''''''''''''''''''''''''''''
    ' Declare ResultArray as a dynamic array
    ' to be resized based on the values of
    ' Low and High.
    '''''''''''''''''''''''''''''''''''''''''
    Dim ResultArray() As Long
    Dim Ndx As Long
    Dim Val As Long
    '''''''''''''''''''''''''''''''''''''''''
    ' Ensure Low <= High
    '''''''''''''''''''''''''''''''''''''''''
    If Low > High Then
        Exit Function
    End If
    '''''''''''''''''''''''''''''''''''''''''
    ' Resize the array
    '''''''''''''''''''''''''''''''''''''''''
    ReDim ResultArray(1 To (High - Low + 1))
    ''''''''''''''''''''''''''''''''''''''''
    ' Fill the array with values.
    ''''''''''''''''''''''''''''''''''''''''
    Val = Low
    For Ndx = LBound(ResultArray) To UBound(ResultArray)
        ResultArray(Ndx) = Val
        Val = Val + 1
    Next Ndx
    ''''''''''''''''''''''''''''''''''''''''
    ' Return the array.
    ''''''''''''''''''''''''''''''''''''''''
    LoadNumbers = ResultArray()

End Function

Note that the array Arr in AAATest has the same data type (Long) as the array returned by LoadNumbers. These data types must match. You cannot declare Arr in AAATest as an array of Variants to receive an array of any data type. If you do, you'll receive a "Can't Assign To Array" compiler error. You will receive the same compiler error if Arr is a static array. The array that is set to the return value of a function must be a dynamic array. It may be allocated, in which case it will be resized automatically to hold the result array, either increasing or decreasing its size. It is not required, though, that the receiving array be allocated.  Regardless of whether the receiving array is allocated, it will be automatically sized to match the size of the returned array. 

You can, however, declare the receiving variable as a single Variant. For example, you could use

Dim Arr As Variant
in place of
Dim Arr() As Long

For example, in the following code, the Arr array will be resized from 100 down to 10 when it receives the result of the LoadNumbers function.

Sub AAATest()
    Dim Arr() As Long
    Dim N As Long
    ReDim Arr(1 To 100)
    Debug.Print "BEFORE LoadNumbers: Number Of Elements in Arr: " & CStr(UBound(Arr) - LBound(Arr) + 1)
    Arr = LoadNumbers(Low:=101, High:=110)
    Debug.Print "AFTER LoadNumbers: Number Of Elements in Arr: " & CStr(UBound(Arr) - LBound(Arr) + 1)
End Sub
Function LoadNumbers(Low As Long, High As Long) As Long()
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' LoadNumbers
    ' Returns an array of Longs containing the numbers 
    ' between Low and High.
    ''''''''''''''''''''''''''''''''''''''''''''''''' 
    Dim ResultArray() As Long
    Dim Ndx As Long
    Dim Val As Long
    If Low > High Then
        Exit Function
    End If
    ReDim ResultArray(1 To (High - Low + 1))
    Val = Low
    For Ndx = LBound(ResultArray) To UBound(ResultArray)
        ResultArray(Ndx) = Val
        Val = Val + 1
    Next Ndx
    LoadNumbers = ResultArray()
End Function

If the receiving array has a base index (LBound) that differs from the array it receives, the receiving array will take on a new base value from the returned array. For example,

    Sub AAATest()
        Dim Arr() As Long
        Dim N As Long
        '''''''''''''''''''''''''''
        ' Set the lower and upper
        ' bounds of Arr to 0 and 9
        ' respectively.
        '''''''''''''''''''''''''''
        ReDim Arr(0 To 9)
        Debug.Print "BEFORE LoadNumbers: LBound: " & CStr(LBound(Arr)) & "  UBound: " & CStr(UBound(Arr))
        ' LoadNumbers uses the a lower bound of 1, not 0
         Arr = LoadNumbers(Low:=101, High:=110)
        ' Note that the LBound is now 1 and the UBound is now 10.
        Debug.Print "AFTER LoadNumbers:  LBound: " & CStr(LBound(Arr)) & "  UBound: " & CStr(UBound(Arr))
    End Sub

The code above shows that the LBound of Arr was changed from 0 to 1, the LBound of the result array declared and allocated in the  LoadNumbers procedure.

A function can also return a Variant containing an array. Even in this case, the receiving array must have the same data type as the array that is stored in the Variant. For example,

Sub AAATest()
    Dim Arr() As Long
    Dim N As Long
    Arr = LoadNumbers(Low:=101, High:=110)
    If IsArrayAllocated(Arr:=Arr) = True Then
        For N = LBound(Arr) To UBound(Arr)
            Debug.Print Arr(N)
        Next N
    Else
        ''''''''''''''''''''''''''''''''''''
        ' Code in case Arr is not allocated.
        ''''''''''''''''''''''''''''''''''''
    End If
End Sub

Function LoadNumbers(Low As Long, High As Long) As Variant ' note we return Variant, not Long()
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' LoadNumbers
    ' Returns a Variant containing an array containing
    ' the numbers between Low and High.
    ''''''''''''''''''''''''''''''''''''''''''''''''' 
    Dim ResultArray() As Long
    Dim Ndx As Long
    Dim Val As Long
    If Low > High Then
        Exit Function
    End If
    ReDim ResultArray(1 To (High - Low + 1))
    Val = Low
    For Ndx = LBound(ResultArray) To UBound(ResultArray)
        ResultArray(Ndx) = Val
        Val = Val + 1
    Next Ndx
    LoadNumbers = ResultArray()
End Function

If the calling procedure doesn't know what type of data will be in the array returned by a function, it can use a Variant variable to store the result. The Variant will contain the array. Since this version of LoadNumbers returns a Variant, we can make no assumptions about what it might return. The code should test for all contingencies to avoid an unexpected run-time error.

Sub AAATest()
    Dim Arr As Variant  ' note this is declared As Varaint, not As Long()
    Dim N As Long
    Arr = LoadNumbers(Low:=101, High:=110)
    '''''''''''''''''''''''''
    ' Ensure Arr is an array.
    '''''''''''''''''''''''''
    If IsArray(Arr) = True Then
        ''''''''''''''''''''''''''''''''
        ' Ensure the array is allocated.
        ''''''''''''''''''''''''''''''''
        If IsArrayAllocated(Arr:=Arr) = True Then
            ''''''''''''''''''''''''''''''''
            ' Ensure Arr is one-dimensional.
            ''''''''''''''''''''''''''''''''
            If NumberOfArrayDimensions(Arr:=Arr) = 1 Then
                '''''''''''''''''''''''''''''''''
                ' Loop through the returned array
                '''''''''''''''''''''''''''''''''
                For N = LBound(Arr) To UBound(Arr)
                    ''''''''''''''''''''''''''
                    ' Ensure Arr(N) is numeic.
                    ''''''''''''''''''''''''''
                    If IsNumeric(Arr(N)) = True Then
                        Debug.Print Arr(N)
                    Else
                        Debug.Print "Arr(N) is not numeric."
                        '''''''''''''''''''''''''''''''''''''
                        ' Code in case Arr(N) is not numeric.
                        '''''''''''''''''''''''''''''''''''''
                    End If
                Next N
            Else
                Debug.Print "Arr is not one-dimensional."
                ''''''''''''''''''''''''''''''''''''''''
                ' Code in case Arr is multi-dimensional.
                ''''''''''''''''''''''''''''''''''''''''
            End If
        Else
            Debug.Print "Arr is not allocated."
            ''''''''''''''''''''''''''''''''''''
            ' Code in case Arr is not allocated.
            ''''''''''''''''''''''''''''''''''''
        End If
    Else
        Debug.Print "Arr is not an array."
        '''''''''''''''''''''''''''''''''''
        ' Code in case Arr is not an array.
        '''''''''''''''''''''''''''''''''''
    End If
End Sub

Function LoadNumbers(Low As Long, High As Long) As Variant
   '''''''''''''''''''''''''''''''''''''''''''''''''
    ' LoadNumbers
    ' Returns a Variant containing an array containing
    ' the numbers between Low and High.
    ''''''''''''''''''''''''''''''''''''''''''''''''' 
    Dim ResultArray() As Long
    Dim Ndx As Long
    Dim Val As Long
    If Low > High Then
        Exit Function
    End If 
    ReDim ResultArray(1 To (High - Low + 1))
    Val = Low
    For Ndx = LBound(ResultArray) To UBound(ResultArray)
        ResultArray(Ndx) = Val
        Val = Val + 1
    Next Ndx
    LoadNumbers = ResultArray()
End Function

As you can see, using Variants to store arrays gives you considerably more flexibility, but it also leaves much more room for error or invalid data. If you are using Variants, your code should contain error checking routines to ensure that you are dealing with the type of data you expect.

 
Assigning An Array To An Array
Unfortunately, VBA doesn't let you assign one array to another array, even if the size and data types match. For example, the following code will not work:

    Dim A(1 To 10) As Long
    Dim B(1 To 10) As Long
    ' load B with data
    A = B

You can, however,  assign a Variant containing an array to another Variant. The following code is perfectly legal:

    Dim A As Variant
    Dim B As Variant
    Dim N As Long
    A = Array(11, 22, 33)
    B = A
    Debug.Print "IsArray(B) = " & CStr(IsArray(B))
    For N = LBound(B) To UBound(B)
        Debug.Print B(N)
    Next N

If you need to transfer the contents of one array to another, you must loop through the array element-by-element:

    Dim A(1 To 3) As Long
    Dim B(0 To 5) As Long
    Dim NdxA As Long
    Dim NdxB As Long

    A(1) = 11
    A(2) = 22
    A(3) = 33
    NdxB = LBound(B)
    For NdxA = LBound(A) To UBound(A)
        If NdxB <= UBound(B) Then
            B(NdxB) = A(NdxA)
        Else
            Exit For
        End If
        NdxB = NdxB + 1
    Next NdxA

    For NdxB = LBound(B) To UBound(B)
        Debug.Print B(NdxB)
    Next NdxB

The code above will transfer the contents of array A to array B. It does this successfully even if A and B have different LBounds, and will terminate the loop of the UBound of B is exceeded, which would be the case if A contains more elements than B. If A contains fewer elements than B, the unused elements of B will remain intact. If you want to ensure the B is "clean" before transferring the elements of A to it, use the Erase statement and, if B is a dynamic array, ReDim it back to its original size, as shown below:

    Dim SaveLBound As Long
    Dim SaveUBound As Long
    SaveLBound = LBound(B)
    SaveUBound = UBound(B)
    Erase B
    If IsArrayDynamic(Arr:=B) = True Then
        ReDim B(SaveLBound, SaveUBound)
    End If
 
Multi-Dimensional Arrays

So far, all of the procedures and techniques described have used single-dimensional arrays. So what about multi-dimensional arrays? The short answer is that the same rules and techniques that apply to single-dimensional arrays apply to multi-dimensional arrays.   On
the Functions For VBA Arrays page, there is a function named NumberOfArrayDimensions that will return the number of dimensions of an array. (It returns 0 for unallocated dynamic arrays).  You can use this function to determine the number of dimensions of either a static or dynamic array. You can pass a multi-dimensional array to a procedure, as shown in the code below.
Sub AAATest()
    Dim N As Long
    Dim Sum As Long
    ''''''''''''''''''''''''''
    ' Declare a dynamic array
    '''''''''''''''''''''''''
    Dim Arr() As Long
    ''''''''''''''''''''''''''
    ' Size the array for two
    ' dimensions.
    ''''''''''''''''''''''''''
    ReDim Arr(1 To 2, 1 To 3)
    ''''''''''''''''''''''''''
    ' Put in some values.
    ''''''''''''''''''''''''''
    Arr(1, 1) = 1
    Arr(1, 2) = 2
    Arr(1, 3) = 3
    Arr(2, 1) = 4
    Arr(2, 2) = 5
    Arr(2, 3) = 6
    '''''''''''''''''''''''''''
    ' SumMulti will return the
    ' sum of the element in a
    ' 1 or 2 dimensional array.
    '''''''''''''''''''''''''''
    Sum = SumMulti(Arr:=Arr)
    Debug.Print Sum
End Sub

Function SumMulti(Arr() As Long) As Long
    Dim N As Long
    Dim Ndx1 As Long
    Dim Ndx2 As Long
    Dim NumDims As Long
    Dim Total As Long
    ''''''''''''''''''''''''''''''''''''''''''
    ' Get the number of array dimensions.
    ' NumberOfArrayDimensions will return 0
    ' if the array is not allocated.
    '''''''''''''''''''''''''''''''''''''''''
    NumDims = NumberOfArrayDimensions(Arr:=Arr)
    Select Case NumDims
        Case 0
            ''''''''''''''''''''''''''''''''
            ' unallocated array
            ''''''''''''''''''''''''''''''''
            SumMulti = 0
            Exit Function
        Case 1
            ''''''''''''''''''''''''''''''''
            ' single dimensional array
            ''''''''''''''''''''''''''''''''
            For N = LBound(Arr) To UBound(Arr)
                 Total = Total + Arr(N)
            Next N
        Case 2
            '''''''''''''''''''''''''''''''''
            ' 2 dimensional array
            '''''''''''''''''''''''''''''''''
            For Ndx1 = LBound(Arr, 1) To UBound(Arr, 1)
                For Ndx2 = LBound(Arr, 2) To UBound(Arr, 2)
                    Total = Total + Arr(Ndx1, Ndx2)
                Next Ndx2
            Next Ndx1
        Case Else
            ''''''''''''''''''''''''''''''''
            ' Too many dimensions.
            ''''''''''''''''''''''''''''''''
           MsgBox "SumMulti works only on 1 or 2 dimensional arrays."
           Total = 0
    End Select
    ''''''''''''''''''
    ' return the total
    ''''''''''''''''''
    SumMulti = Total
End Function

Functions can return multi-dimensional arrays just as they can single-dimensional arrays. The same rules apply: the array receiving the result must be a dynamic array and must have the same data type as the returned array.  For example,

Sub AAATest()
    ''''''''''''''''''''''''
    ' Dynamic array to hold
    ' the result.
    ''''''''''''''''''''''''
    Dim ReturnArr() As Long
    Dim Ndx1 As Long
    Dim Ndx2 As Long
    Dim NumDims As Long
    ''''''''''''''''''''''''''
    ' call the function to get
    ' the result array.
    ''''''''''''''''''''''''''
    ReturnArr = ReturnMulti()
    NumDims = NumberOfArrayDimensions(Arr:=ReturnArr)
    Select Case NumDims
        Case 0
            '''''''''''''''''''
            ' unallocated array
            '''''''''''''''''''
        Case 1
            ''''''''''''''''''''''''''
            ' single dimensional array
            ''''''''''''''''''''''''''
            For Ndx1 = LBound(ReturnArr) To UBound(ReturnArr)
                Debug.Print ReturnArr(Ndx1)
            Next Ndx1
        Case 2
            '''''''''''''''''''''''''''
            ' two dimensional array
            '''''''''''''''''''''''''''
            For Ndx1 = LBound(ReturnArr, 1) To UBound(ReturnArr, 1)
                For Ndx2 = LBound(ReturnArr, 2) To UBound(ReturnArr, 2)
                    Debug.Print ReturnArr(Ndx1, Ndx2)
                Next Ndx2
            Next Ndx1
        Case Else
            ''''''''''''''''''''''
            ' too many dimensions
            ''''''''''''''''''''''
    End Select
End Sub


Function ReturnMulti() As Long()
    ''''''''''''''''''''''''''''''''''''
    ' Returns a mutli-dimensional array.
    ''''''''''''''''''''''''''''''''''''
    Dim A(1 To 2, 1 To 3) As Long
    '''''''''''''''''''''''''''''
    ' put in some values.
    '''''''''''''''''''''''''''''
    A(1, 1) = 100
    A(1, 2) = 200
    A(1, 3) = 300
    A(2, 1) = 400
    A(2, 2) = 500
    A(2, 3) = 600
    ReturnMulti = A()
End Function

 


Looping Through Arrays
You may have noticed that when looping through the arrays, all the  code above uses LBound(Arr)  and UBound(Arr) as the lower and upper limits of the 
loop index. This is the safest way to loop through an array. This will properly set the loop index variable bounds regardless of how the array was sized, and 
regardless of the Option Base module setting. Good programming practice dictates that you use LBound and UBound rather than hard-coding the lower 
and upper values for the loop index. It is a bit more typing, but will ensure that the complete array is looped through and will avoid Subscript Out Of Range run time errors.

Using arrays is a powerful technique in VBA, and passing and returning arrays to and from function only adds to the range of possibilities of your code.
Properly understanding how to pass arrays between procedures is a critical to successfully using array in your applications.