No trailing closures support for methods with default parameter values?
It does look like a problem with trailing closures - this code works:
object.bar(b: { () -> () in
println("foo")
})
However if the external name is removed:
func bar(a: String = "a", _ b: () -> ()) {
b()
}
this no longer works:
object.bar({ () -> () in
println("foo")
})
Moreover using a function having a string as the 2nd parameter:
func test( val1: String = "a", val2: String) {
}
the default parameter is correctly assigned, so this succeeds:
test("me")
which is a different behavior than using closures.
Conclusion: a method or function with parameter(s) having default value and a trailing closure does not work if at least one of the parameters with default value is not specified. Avoiding the trailing closure the function works only if the parameter has external name.
Can swift closures be set to a default value when used as a parameter in a function?
Yes, functions are just values, so you can supply them as defaults
// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }
func sendBody(
body: NSData? = nil,
success: (data: NSData) -> Void = { _ in return },
failure: (data: NSData?) -> Void = doNothing
)
{ }
Alternatively, you could make them optional, that way you can detect if the caller passed one:
func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{ success?(NSData()) }
sendBody(success: { _ in print("ah, yeah!") })
Also worth noting if you’re doing this: if the caller uses the trailing closure syntax, this will be the last closure in the argument list. So you want the last one to be the one the user is most likely to want to supply, which is probably the success closure:
func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{
if success != nil { print("passed a success closure") }
if failure != nil { print("passed a failure closure") }
}
// this prints "passed a failure closure"
sendBody { data in
print("which closure is this?")
}
Other than this, the order in the function declaration doesn’t matter to the caller – defaulted arguments can be supplied in any order.
How to have an optional trailing closure?
I'm not sure you've got your definition of optional entirely correct. It doesn't mean you don't need to supply a value for the closure
argument; it means closure
can either have a value (of a closure in your case) or be nil
. Therefore, if you wanted to call hello
without providing a closure you would write:
hello("abc", nil)
However, you can achieve what you're after using default parameter values (I'd recommend you have a look at The Swift Programming Guide: Functions). Your function would be:
// Note the `= nil`:
func hello(message: String, closure: ((msg: String ) -> Void)? = nil) {
println("called hello with: \(message)")
closure?(msg: message)
}
// Example usage:
hello("abc")
hello("abc") { println($0) }
Swift: function with default parameter before non-default parameter
The current compiler does allow default parameters in the middle of a parameter list.
You can call the function like this if you want to use the default value for the first
parameter:
f(1)
If you want to supply a new value for the first
parameter, use its external name:
f(first: 3, 1)
The documentation explains that parameters with a default value are automatically given an external name:
Swift provides an automatic external name for any defaulted parameter you define, if you do not provide an external name yourself. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code.
How come and when is it possible to use shorter method signatures in Swift?
That particular shorthand is possible for two reasons: default values for input parameters and trailing closures.
Have a look at the actual type signature for the function:
func async(group: DispatchGroup? = default, qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, execute work: @escaping () -> Void)
You can clearly see that all input parameters have default values except for the closure. If you omit any of these, the compiler will use the default value.
Since work
is a closure, which is the last input parameter to the function, as a shorthand notation, you can move it outside the parentheses and just write it after the function call, which is called a trailing closure.
Implicit parameters in trailing closure
In
doMathOperation(4, 5, operation: multiply)
...you are being asked for a function that takes two Double parameters, and multiply
is the name of just such a function, so it compiles and works.
In
doMathOperation(4, 5) { ... }
the curly braces themselves are the (body of the) function that takes two Double parameters. It makes no sense to put the name of another such function inside the curly braces.
But of course you are free to call any function you like, passing along the parameters that were passed to you; hence this works:
doMathOperation(4, 5) { multiply($0,$1) }
So, just to sum up: In the first one
doMathOperation(4, 5, operation: multiply)
there is one function, multiply
, and 4 and 5 are passed to it. In the second one
doMathOperation(4, 5) { multiply($0,$1) }
there are two functions, "anonymous" (the curly braces) and multiply
, and the 4 and 5 are passed into the first one and then it calls the second one.
Related Topics
Swift Xcode 7 Beta 5 Type Cannot Refer to Itself as a Requirement
Weird Toolbar with Nested Conditionals Behavior
Dynamically Set Properties from Dictionary<String, Any> in Swift
How to Dynamically Hide Navigation Back Button in Swiftui
Why Do I Get Rgb Values of (0,0,0) for an Nsimage with a Transparent Background
Adding Drop Shadow to Table View Cell
Swift Auto Completion Not Working in Xcode 6 Beta
Cannot Convert Value of Type 'Nsmutablearray' to Expected Argument Type '[Skaction]'
Swift Optionals Best Practices
Swift 3: Convert a String to an Array
How Does Swift Disambiguate Type Arguments in Expression Contexts
What Do Detached and Assigncurrentcontext Meaning
Can't Set @Ibinspectable Computed Property in UIview
Using Enumerated with Foreach in Swiftui
Way to Check If Up or Down Button Is Pressed with Nsstepper