Search code examples
vbaparamarray

Unpacking Array into ParamArray in VBA


Given an array of unknown size and a procedure that accepts a Parameter Array, how can one pass the array as the parameter array without modifying the procedure?

Sub Example(sequence() As String)
    UnModifiableSub sequence
End Sub

Sub UnModifiableSub(ParamArray bar())
    ' bar(0) = sequence not bar = sequence
End Sub

I'm looking behavior similar to Python's unpacking

def foo(*args):  # identical to ParamArray
    print(args)

x = [1,2,3,4]
foo(*x)  # what VBA can't do

I know there is no built-in solution like there is in Python but any cruel implementation is acceptable other than a long switch statement.


Solution

  • The giant switch statement sounds kind of cruel to me, but that's what you're in for if the routine you must call is truly unmodifiable. In VBA, that's a Select Case statement. And don't forget that VBA arrays can have arbitrary indices, so you have to test both LBound and UBound unless you're sure where your sequence argument is coming from.

    If you can write your own routine, there is a a way to mostly do what you want. You can assign an array to a variable of type Variant, like so:

    Sub tryThis(v)
        Debug.Assert IsArray(v)
        Debug.Print v(LBound(v))
    End Sub
    
    Sub Example(sequence() As String)
        tryThis sequence
    End Sub
    
    Sub test()
        Dim s() As String
    
        ReDim s(1 To 2)
        s(1) = "a"
        s(2) = "b"
    
        Call Example(s)
    End Sub
    

    tryThis() takes the place of your UnModifiableSub. If you run test() in the Immediate window you get this output:

    call test
    a
    

    I think that's the behavior you want. (Somewhat, anyway. Nobody wants arbitrary array indices.) Of course, this is limited compared to Python. Notably, if you want to call tryThis(), you must put your "parameters" into an array yourself. Some of the tradeoffs related to doing that are discussed in this answer and the parent question:

    What is the benefit of using ParamArray (vs a Variant array)?

    There are some other issues as well. For example, you can't just pass the contents of a ParamArray to tryThis():

    'Doesn't work...
    Sub gotcha(ParamArray pa())
    
        'Can't do it this way! "Invalid ParamArray use"
        Call tryThis(pa)
    End Sub
    

    You have to make the transfer to a variable explicitly:

    Sub gotchaFixed(ParamArray pa())
        Dim v
        v = pa
    
        Call tryThis(v)
    End Sub
    
    Sub test2()
        Call gotchaFixed("a", "b")
    End Sub
    

    ...

    call test2
    a