Passing Variadic Parameters in Swift
Tags: swift
Published: 2021-02-07 16:57:28

As a Swift developer you might have seen three period characters (...) after a function parameter’s type name.

```swift
func handle(_ numbers: Double...) { }
```

This is a variadic parameter. According to the [Swift documentation](https://docs.swift.org/swift-book/LanguageGuide/Functions.html]) 

> A variadic parameter accepts zero or more values of a specified type. You use a variadic parameter to specify that the parameter can be passed a varying number of input values when the function is called.

The values passed to a variadic parameter are made available within the function’s body as an array of the appropriate type. In our example, you will access `numbers` as a constant array of type `[Double]`.

```swift
func handle(_ numbers: Double...) {
  // numbers is of type `[Double]`
  for number in numbers {
    // number is of type `Double`
  }
}
```

Is it possible to forward the variadic parameter to another function that has a variadic parameter of the same type? Let's try it:

```swift
func publicFacingAPI(_ numbers: Double...) {
    handle(numbers) // ERROR: Cannot pass array of type `[Double]` as variadic arguments of type `Double`
}
```

It appears Swift doesn't like the idea. The most straightforward approach is to keep `publicFacingAPI ` with the variadic parameter and change the argument type of the inner function to `[Double]`.

---

There is another approach (which I do NOT recommend) by using `Any` as type of the variadic parameter. Because a variadic parameter of type `Any` can be forwarded to another function with variadic parameter of type `Any` 🤪.

The obvious drawback is that you will lose helpful type information. But there is another serious implication. The forwarded parameter will become a _nested array_ **whenever you forward it**.
If, at some point, the variadic parameter is declared optional then it gets even more difficult. Here is an extreme example.

```swift
callFunctionWithAnyVariadicParameter(1, 2, 3, Optional<Any>(nil), 5)

func callFunctionWithAnyVariadicParameter(_ p: Any...) {
    forwardAnyVariadicParameter(p)
}

func forwardAnyVariadicParameter(_ p: Any...) {
    forwardAnyVariadicParameterAgain(p)
}

func forwardAnyVariadicParameterAgain(_ p: Any...) {
    forwardAnyVariadicParameterAgainAndAgain(p)
}

func forwardAnyVariadicParameterAgainAndAgain(_ p: Any?) {
    handle(p)
}

func handle(_ p: Any...)  {
    print(p) // [Optional([[[1, 2, 3, nil, 5]]])]
}
``` 

You might think this is extreme. I agree 😊.
You might think is not realistic. Unfortunately, I found this in a real project I was working on 😔. There were (some) reasons why this was done and I had no time to refactor it.

To make life easier and deconstruct a nested type into a simple array and filtering out the `nil` values I wrote an extension on `Array`.

```swift
func handle(_ p: Any...)  {
    print(p.flatCompactMapForVariadicParameters()) // [1, 2, 3, 5]
}
``` 

I hope you found this interesting and please use variadic parameters carefully 😉

For the curious here is the source code of the extension 

{% gist https://gist.github.com/MarcoEidinger/8679ccc283835255a82c7a2110da2974 %}