How can I assign a Variant to a Variant in VBA? How can I assign a Variant to a Variant in VBA? vba vba

How can I assign a Variant to a Variant in VBA?


In VBA, the only way to assign a Variant to a variable where you don't know if it is an object or a primitive, is by passing it as a parameter.

If you cannot refactor your code so that the v is passed as a parameter to a Sub, Function or Let Property (despite the Let this also works on objects), you could always declare v in module scope and have a dedicated Sub solely for the purpose of save-assigning that variable:

Private v As VariantPrivate Sub SetV(ByVal var As Variant)    If IsObject(var) Then        Set v = var    Else        v = var    End IfEnd Sub

with somewhere else calling SetV SomeMethod().

Not pretty, but it's the only way without calling SomeMethod() twice or touching its inner workings.


Edit

Ok, I mulled over this and I think I found a better solution that comes closer to what you had in mind:

Public Sub LetSet(ByRef variable As Variant, ByVal value As Variant)    If IsObject(value) Then        Set variable = value    Else        variable = value    End IfEnd Sub

[...] I guess there just is no LetSet v = ... statement in VBA

Now there is: LetSet v, SomeMethod()

You don't have a return value that you need to Let or Set to a variable depending of its type, instead you pass the variable that should hold the return value as first parameter by reference so that the Sub can change its value.


Dim v As VariantFor Each v In Array(SomeMethod())    Exit For 'Needed for v to retain it's valueNext v'Use v here - v is now holding a value or a reference


You could use error trapping to reduce the expected number of method calls. First try to set. If that succeeds -- no problem. Otherwise, just assign:

Public counter As LongFunction Ambiguous(b As Boolean) As Variant    counter = counter + 1    If b Then        Set Ambiguous = ActiveSheet    Else        Ambiguous = 1    End IfEnd FunctionSub test()    Dim v As Variant    Dim i As Long, b As Boolean    Randomize    counter = 0    For i = 1 To 100        b = Rnd() < 0.5        On Error Resume Next            Set v = Ambiguous(b)            If Err.Number > 0 Then                Err.Clear                v = Ambiguous(b)            End If        On Error GoTo 0    Next i    Debug.Print counter / 100End Sub

When I ran the code, the first time I got 1.55, which is less than the 2.00 you would get if you repeated the experiment but with the error-handling approach replaced by the naïve if-then-else approach you discussed in your question.

Note that the more often the function returns an object, the less function calls on average. If it almost always returns an object (e.g. that is what it is supposed to return but returns a string describing an error condition in certain cases) then this way of doing things will approach 1 call per setting/ assigning the variable. On the other hand -- if it almost always returns a primitive value then you will approach 2 calls per assignment -- in which case perhaps you should refactor your code.