How do I permanently change the value of a variable in an array? I wrote some code that illustrates my problem:
Option Explicit Dim var1 As Boolean, var2 As Boolean, var3 As Boolean Sub Test() Dim arrTest As Variant Dim i arrTest = Array(var1, var2, var3) For Each i In arrTest Debug.Print i Next For i = LBound(arrTest) To UBound(arrTest) arrTest(i) = True Next For Each i In arrTest Debug.Print i Next Test2 End Sub Sub Test2() Debug.Print "var1 in Sub Test2 : " & var1 If var1 Then Debug.Print "Hello" End If End Sub
The output in the direct window is:
False False False True True True var1 in Sub Test2 : False
The first six lines make sense to me because I changed the value of the variables in
Test. However, it obviously wasn’t permanent or it was confined to that one sub and so “Hello” in
Test2 didn’t get printed.
How do I change this? I’ve read that
for each loops are read-only, but why does the
for-loop not work?
Assigning “True” to every element of array does not make your variables same value.
Nothing weird your var1 is still False, because You didn’t change the value of var1, but the value of your array elements. 🙂
Add something like this
var1 = arrTest(0) var2 = arrTest(1) var3 = arrTest(2) Test2
When you do
arrTest = Array(var1, var2, var3) you copy the values of your variables into the arrTest. You do NOT create a reference to those variables.
Since arrTest is declared in Test() its scope is limited to Test().
If you declare arrTest at the module level, you will be able to check arrTest values from Test2. But anyway they will be completely independent from varx.
The behaviour is different if we speak about
Objects. When we write
Set x = obj1 we DO create a reference, and in that case a change in obj1 will be visible in x.
arrTest is a local variant variable for the
Test sub. And this variable takes some public boolean values in it, which are passed ByVal. If the array is declared outside the Subs itself, then it would be accessible from everywhere, exactly the way it is intended:
Option Explicit Option Base 0 Dim arrTest() As Variant Sub Test() Dim i arrTest = Array(False, False, False) For Each i In arrTest Debug.Print i Next For i = LBound(arrTest) To UBound(arrTest) arrTest(i) = True Next For Each i In arrTest Debug.Print i Next Test2 End Sub Sub Test2() Debug.Print arrTest(LBound(arrTest)) 'or arrTest(0) End Sub
If you need to use variables inside array and pass them as a reference, and not as a copy, the OOP in VBA may help. Create a class “Container”, holding a property
SomeValue, encapsulated in
Class is like creating a
Module in VBA:
Private valueKept As String Public Property Get SomeValue() As String SomeValue = valueKept End Property Public Property Let SomeValue(ByVal myValue As String) valueKept = myValue End Property
SomeValue property of this class, could be changed ByRef, when the
Container object is put in array:
Sub Test() Dim myArr As Variant Dim c1 As New Container Dim c2 As New Container c1.SomeValue = 5 c2.SomeValue = 10 myArr = Array(c1, c2) Test2 myArr Debug.Print c1.SomeValue '55 End Sub Sub Test2(myArr As Variant) myArr(0).SomeValue = 55 End Sub