How to use a variadic closure in swift?
Compiler limitation/bug with argument type inference for single-expression closures
I believe the source of this is a current limitation (/bug) in the compiler w.r.t. inferring the argument types in single-line closures using variadic parameters, see e.g. the following Q&A
- Why can't I use .reduce() in a one-liner Swift closure with a variadic, anonymous argument?
A similar issue was also present for inout
arguments in Swift 2.1 (but no longer in 2.2), as is explained in the following thread
- Inline if statement mutating inout parameter in a void return closure, weird error (Error: type 'Int1' does not conform to protocol 'BooleanType')
Looking at thread 1. as well as attempting to find the described bug flagged in Swift JIRA, however, it seems as if the OP of thread 1. never filed a bug for this, after all. Possibly I just haven't found an existing bug report, but if none exists, one should possibly be filed.
Current workarounds
Possible workarounds, until the compiler's closure argument type inference catches up, are
Extend the closure beyond single-line body
// ...
[1, 2].satisfy { (args) in
() // dummy
print (args) // [1, 2, 3]
}Or, explicitly include type of
args
, e.g.[1, 2].satisfy { (args: Int...) in
print (args) // [1, 2, 3]
}Note that
Generator.Element
resolves toInt
in this example above.
Current status for Swift 3.0-dev
As mentioned briefly above, curiously enough, this bug
inout: is apparently no longer present in Swift 2.2 or Swift 3.0-dev for
inout
arguments, w.r.t. the issues described in Q&A 2. as linked to above- it was possibly fixed as bug [SR-7] was resolved (-> Swift 2.2)
however, seems to be regression 2.2->3.0-dev, w.r.t. type inference for
inout
arguments, as reported in bug report [SR-892]. E.g. the following snippet works in Swift 2.2, but not in 3.0-dev (minimally modified snipper from bug report [SR-7])func f(inout a: Int) {}
let g = { x in f(&x) } // OK 2.2, crashes 3.0-dev
variadic: is still present in Swift 2.2 as well as Swift 3.0-dev for variadic arguments (this thread and Q&A 1. above).
a more condensed example of the bug:
let a: (Int...) -> () = { (args) in print(args) } // bug: crashes
let b: (Int...) -> () = { (args: Int...) in print(args) } // explicitly state argument type, OK
let c: (Int...) -> () = { (args) in (); print(args) } // extend to more than single line closure, OK
(For Swift 3.0-dev, tested using the IBM Swift Sandbox running Swift 3.0-dev.
Swift Variadic Closures Syntax?
Try to specify parameter type and return type in closure to helps compiler to understand what value it should take and return. Also, you have a mistake in for
loop. The interval should be like this 0 ..< values.count
:
func isAllAbove(lower: Double) -> (Double...) -> Bool {
return { (values: Double...) -> Bool in
var conditions: [Bool] = []
for i in 0 ..< values.count {
conditions.append(lower < values[i])
}
return !conditions.contains(false)
}
}
let allAbove = isAllAbove(lower: 2)
print(allAbove(1, 2, 3)) // false
Also, you can write it almost in 1 line of code:
let lower = 2
let isAllAbove = ![1, 2, 3].contains { $0 < lower }
print(isAllAbove1) // false
Is it possible to use Variadic Parameters within Closures?
You need to include the type in the closure:
this { (foo: Int...) in }
The type-inference engine isn't quite powerful enough to figure out this case. I suspect it's related to SR-6030.
Marking a variadic closure parameter as escaping
You don't need to use @escaping
here at all. Only a closure that is directly an argument (with nothing wrapping it) can be non-escaping.
A closure that is part of a variadic argument is (under the hood) wrapped in an Array
, so it is already implicitly @escaping
.
For example, this compiles and runs just fine:
class MyObject {
var closures: [() -> ()] = []
func add(_ closures: () -> () ...) {
self.closures += closures
}
func run() {
for closure in closures { closure() }
}
}
let object = MyObject()
object.add({ print("first") }, { print("second") })
object.run()
Variadic @autoclosure's in Swift 1.2?
I opened rdar://19782845, "Swift 1.2: Variadic auto-closures no longer supported," and was given the following response from Apple Developer Relations:
This issue behaves as intended based on the following:
@autoclosure is only allowed on parameters of function type, and varargs is an array. This is not expected to work.
Swift Programming -- Function And Closure
Those ...
mean that the function can take a variable number of arguments
From the The Swift Programming Language book:
Variadic Parameters
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.
Write variadic parameters by inserting three period characters (...)
after the parameter’s type name.The values passed to a variadic parameter are made available within
the function’s body as an array of the appropriate type. For example,
a variadic parameter with a name of numbers and a type of Double... is
made available within the function’s body as a constant array called
numbers of type [Double].
Related Topics
Function That Takes a Protocol and a Conforming Class (!) Instance as Parameters
Swiftui: How to Make a Button Open a Url in Safari
Swift Protocol to Require Properties as Protocol
Playing a Sound in a Swift Playground
Swift Can't Infer Generic Type When Generic Type Is Being Passed Through a Parameter
Missing Argument for Parameter 'From' in Call When Creating Instance of Codable Class
How to Handle Two Different Types in an Array in Swift for a Uitableview
Swift, Sprite Kit Game: Have Circle Disappear in Clockwise Manner? on Timer
Swift & Firebase - How to Store More User Data Other Than Email and Password
Is There a Daylight Savings Check in Swift
Extend Generic Array<T> to Adopt Protocol
Using Applescript with Apple Events in MACos - Script Not Working
How to Implement iOServicematchingcallback in Swift
Instance Member Cannot Be Used on Type Class
Swift/Firebase - Sort Posts in Tableview by Date
Difference Between Nsrange and Nsmakerange
Swift Task Continuation Misuse: Leaked Its Continuation - for Delegate