What's the reason behind the fact that variadic parameters in functions can't have default values?

For example

func foo(
    bar: Int... = [1, 2, 3] // error
) { }

I couldn't find any discussion on this in the forums, and it feels like an inconsistency. Was it decided early on that this wouldn't be allowed? Is there something fundamental preventing it? Is this a feature worth pitching?

1 Like

[Variadics are a topic where people seem to be quite passionate about, but I'm absolutely convinced that the current implementation really doesn't pull it's own weight, and you just discovered another quirk]

Afaik, variadics are a type on their own - and they are very special:
You can only use them in one single place (method signature), and they magically turn into arrays when they are used.
Therefor, you cannot initialize a variadic argument with an array (and the syntax without [] isn't allowed either.

There's a very simple solution to this and other issues, but people seem to love some special cases like this :man_shrugging:
See [Discussion] Variadics as an Attribute or search for variadics (there are many threads about the topic).
Basically, it's about getting rid of the special syntax and turn variadics into pure sugar for arguments that can be initialized with an array literal (that would be more than just arrays, which is one of the many benefits of this approach)

Variadic parameters in Swift accept an empty list of arguments (unlike C, for example, but like in Java). And this is why there is no such thing as default variadic values:

func foo(bar: Int...) {
    print(bar)
}

foo(bar: 1, 2) // prints "[1, 2]"
foo()          // prints "[]"

One could say there is already a default value, and this default value is the empty array (but this certainly is a language abuse, and not an accurate framing of the topic).

You can mimic default values by checking for emptiness:

func foo(bar: Int...) {
    if bar.isEmpty {
        print("[1, 2, 3]")
    } else {
        print(bar)
    }
}

foo(bar: 1, 2) // prints "[1, 2]"
foo()          // prints "[1, 2, 3]"
3 Likes

You can force at least one argument:

func foo(bar: Int, _ otherBars: Int...) {
    print([bar] + otherBars)
}

foo(bar: 1, 2) // prints "[1, 2]"
// foo()       // does not compile

But now it is uneasy to mimic a default value, since you have two independent arguments. A possible solution is to define two distinct functions:

func foo(bar: Int, _ otherBars: Int...) {
    print([bar] + otherBars)
}

func foo() {
    foo(bar: 1, 2, 3)
}

foo(bar: 1, 2) // prints "[1, 2]"
foo()          // prints "[1, 2, 3]"
1 Like

That's probably what I would do, if possible.