Reputation: 32117
I have the following swift function:
func foo(bar: String)(_ baz: String) {
NSLog("bar \(bar), baz: \(baz)")
}
let f = foo("fizz")("buzz") // won't compile, foo returns Void
I want to pass that to dispatch_async
, but I can't because I can't curry both parameters without invoking the function. How do I curry both bar
and baz
without calling the foo
?
Upvotes: 0
Views: 183
Reputation: 185681
If you are free to change the function declaration, Heath's answer is correct. If you don't want to do that, then you just need to use an inline closure, e.g.
// pre-existing foo definition
func foo(bar: String)(_ baz: String) {
NSLog("bar \(bar), baz: \(baz)")
}
let f = { foo("fizz")("buzz") }
f()
If your problem is you want to evaluate the arguments immediately, you can use a capture list:
let f = { [a=bar(),b=baz()] in foo(a)(b) }
Or when written as a call to dispatch_async
:
dispatch_async(queue) { [a=bar(),b=baz()] in
foo(a)(b)
}
This works because the capture list is evaluated immediately by the caller when the closure is created (as opposed to being evaluated when the closure is invoked).
Another option is to define a nested curried function. Nested functions are really just sugar for closures, but they can be more convenient:
/// Function that your code is executing in
func myFunc() {
// ...
// define a nested function
func f(bar: String, baz: String)() {
foo(bar)(baz)
}
// now call it
dispatch_async(dispatch_get_main_queue(), f("foo", "bar"))
}
Addendum: I strongly recommend against saying NSLog("bar \(bar), baz: \(baz)")
. NSLog
takes a format string and arguments, and so if either bar
or baz
contain anything that looks like a format token (e.g. %@
or %d
) then the call to NSLog()
will behave badly and possibly crash. You have two reasonable options:
NSLog("%@", "bar \(bar), baz: \(baz)")
NSLog("bar %@, baz: %@", bar, baz)
The best option depends on whether your arguments are already compatible with CVarArg
(which String
is but e.g. String?
is not). Also note that if your arguments are guaranteed to not contain format tokens, such as if they're numbers or booleans, then you can go ahead and use your existing NSLog("bar \(someIntVar) baz \(someBoolVar)")
style.
Upvotes: 5
Reputation: 32117
Append an extra set of parens at the end of the function declaration:
func foo(bar: String)(baz: String)() {
NSLog("bar \(bar), baz: \(baz)")
}
let f = foo("fizz")("buzz") // compiles!
f() // logs: "bar fizz, baz: buzz"
Upvotes: 3