I was using String format with variadic parameters, and was very puzzled by how it works.

See this piece of playground code:

let f = "Hello %d World %d"

// Pass [1, 2] directly
String(format: f, arguments: [1, 2])
// Prints "Hello 1 World 2" correctly

// Now, lets create an array [1, 2], and pass in
let arr = [1, 2]

// Surprisingly, this will CRASH
String(format: f, arguments: arr)

This puzzled me.

Looks so similarly, yet one will crash and burn.

Swift Type

Apparently, arguments require the type [CVarArgType], and if you will to declare it like arr as above, the type will be [Int], and that’s not ok.

This thread shed light on why the array is not cast/unpacked automatically.

Should the compiler choose T=Int or T=Int[] ?
Swift’s generics system allows T to be any type, including an array type, so we don’t allow automatic “unpacking” of arrays when calling into variadics, meaning that we’ll always pick T=Int[]. There should be some way to explicitly unpack an array (or any sequence?), and we (internally) have a Radar requesting this feature.

The fix is to explicitly provide the type:

let arr: [CVarArgType] = [1, 2]
String(format: f, arguments: arr)




Back to Home