Why is the shorthand argument name $0 returning a tuple of all parameters?
Closures § Shorthand Argument Names
Shorthand Argument Names
…
the number and type of the shorthand argument names will be inferred from the expected function type.
It looks like this is the expected behavior. By providing only $0
you are inferring (at least to the system) that you want a tuple.
This only seems to be a special case of using $0
. For example, the following cannot be compiled.
var returnAString3: (String, String, String) -> String
returnAString3 = { return $1 }
No matter how it's modified.
returnAString3 = { return $1.0 } // still fails.
Why don't shorthand argument names work in this Swift closure?
It depends on the number of parameters.
For example,
func test( closure: (Int,Int,Int) -> Void ){
// do something
}
To make test
works as you expect, you must specify $2
( 3rd argument ). The compiler will infer to the values inside tuple, otherwise it will infer to the tuple itself.
If you don't specify $number
that match the number of parameters. For example, only specify $1
, will make compile error.
// work as expected ( infer to int )
test{
print($2)
}
test{
print($1+$2)
}
test{
print($0+$1+$2)
}
// not work ( infer to tuple )
test{
print($0)
}
// not work ( cannot infer and compile error )
test{
print($1)
}
There is a question relate to this question. Why is the shorthand argument name $0 returning a tuple of all parameters?
Why does use of closure shorthand-named variables has to be exhaustive in a singular return expression in Swift?
If you just use $0
, the closure arguments are assumed to be a tuple instead of multiple variables $0
, $1
etc. So you should be able to work around this by extracting the first value of that tuple:
print(foo(closure: {$0.0}))
Why can't I use the shorthand argument names in this default parameter value?
callback: ACallback = { $0.0 }
should be OK, I think. As the error describes, $0
means a tuple of entire parameter list of that closure here.
Swift - How to understand Shorthand Argument Names
Because [unowned self] is a closure capture list, it's not an argument.
{
[unowned self] // Capture list
(a:String, b:Int) //Arguments names
in
... //Closure body
}
Capture lists appear as the first item in a closure. They’re listed before any parameter clauses or identifier lists and require the in keyword to be used.
Strong Reference Cycles for Closures from The Swift Programming Language Automatic Reference Counting
....
This strong reference cycle occurs because closures, like classes, are
reference types. When you assign a closure to a property, you are
assigning a reference to that closure. In essence, it’s the same
problem as above—two strong references are keeping each other alive.
However, rather than two class instances, this time it’s a class
instance and a closure that are keeping each other alive.Swift provides an elegant solution to this problem, known as a closure capture list. However, before you learn how to break a
strong reference cycle with a closure capture list, it is useful to
understand how such a cycle can be caused.
Example of closure :
[1, 2, 3].map( { (i: Int) ->Int in return i * 2 } )
[1, 2, 3].map( { i in return i * 2 } )
[1, 2, 3].map( { i in i * 2 } )
[1, 2, 3].map( { $0 * 2 } )
[1, 2, 3].map() { $0 * 2 }
[1, 2, 3].map { $0 * 2 }
Based on source you've provide I believe the original came from
http://rasic.info/bindings-generics-swift-and-mvvm/
class Dynamic<T> {
typealias Listener = T -> Void
var listener: Listener?
func bind(listener: Listener?) {
self.listener = listener
}
func bindAndFire(listener: Listener?) {
self.listener = listener
listener?(value)
}
var value: T {
didSet {
listener?(value)
}
}
init(_ v: T) {
value = v
}
}
Distinguishing Tuple and Multi-Argument Functions
You're correct about the confusion. I'm somewhat going to just restate your understanding, and say "yes, tuples in Swift are weird and slightly broken."
Swift does not distinguish between functions that take tuples vs multiple arguments in some ways, but does distinguish in other ways. (This is one of many reasons to avoid tuples at this point in Swift's life.)
First, these two functions have almost the same type in Swift (note that Void
and ()
are identical):
func tuple(value: (Int, Int) ) {} // (Int, Int) -> Void
func two(value1: Int, value2: Int) {} // (Int, Int) -> Void
They look the same. But if you define a function that accepts that type, it can't take tuple
:
func take(f: (Int, Int) -> Void) {}
take(f: tuple) // Fails
take(f: two) // ok
But if you define a function that takes ((Int, Int)) -> Void
it can accept either function:
func take(f: ((Int, Int)) -> Void) {}
take(f: tuple) // ok
take(f: two) // ok
That suggests that (Int, Int) -> Void
is a subtype of ((Int, Int)) -> Void
.
But variables belie this:
var f: (Int, Int) -> Void
f = tuple // Ok
f = two // Ok
var g: ((Int, Int)) -> Void
g = tuple // ok
g = two // ok
g = f // ok
f = g // ok
And that suggests that (Int, Int) -> Void
and ((Int, Int)) -> Void
are the same type. But the take
function indicates they're not.
Yes. All of that is true at the same time. Functions that accept tuples are not a coherent type in Swift (they do not occupy a clearly-deliniated spot in the type hierarchy). That's just where we are in Swift today.
Old, incorrect answer.
This is just a quirk of Playgrounds, and you should feel free to open a radar about that.
If you check type(of: closure)
, it'll print the type you expect. Swift knows the correct type; Playgrounds just displays the wrong thing.
Swift function with Shorthand Argument Names
This may be a bug or half implemented feature now because I can't find anything in the documentation about it. Using a function like you described compiles and runs fine:
func functionC(Int, String) {
println("function called")
}
functionC(10, "hello")
but attempting to use the arguments with the closure syntax $0
and $1
results in the error: Anonymous closure argument not contained in a closure
which pretty clearly states you aren't allowed to use anonymous arguments in a function.
I think the purpose of this then is to be able to have the same method signature of a required function even if you don't have to use all of the arguments like this example:
protocol myProtocol{
func requiredFunc(Int, String) -> Bool
}
class myClass: myProtocol{
func requiredFunc(x: Int, String) -> Bool{
return x > 10
}
}
Add conditions on shorthand argument name $0 that returns one or two different text views in SwiftUI
With the help of ternary conditional operator I came to this solution that loads buttons with the shorthand argument name $0 inside Button
.
ForEach(self.emojiMoves, id: \.self ) {
Button($0 == " ? " : $0 == " ? " : "✂️") {
}
}
Thank you
What does $0 and $1 mean in Swift Closures?
$0
is the first parameter passed into the closure. $1
is the second parameter, etc. That closure you showed is shorthand for:
let sortedNumbers = numbers.sort { (firstObject, secondObject) in
return firstObject > secondObject
}
Related Topics
Make Code With Firebase Asynchronous
Array Element Cannot Be Bridged to Objective-C
Nsfontattributedstring Worked Before Xcode 6.1
How to Stop Timer in Text View
Swift Write/Save/Move a Document File to Icloud Drive
How to Do If Pattern Matching with Multiple Cases
Swift - Could Not Cast Value of Type '_Nscfstring' to 'Nsdictionary'
Uploading Image to Firebase Storage and Database
Swift Sphere Combine Star Data
Swift 5: What's 'Escaping Closure Captures Mutating 'Self' Parameter' and How to Fix It
Swift5 Macos Imageresize Memory Issue
Init(Start:End:)' Is Deprecated: It Will Be Removed in Swift 3. Use the '..<' Operator
How to Draw Text in PDF Context in Swift
Variable 'Xxx' Was Never Mutated, Consider Changing to 'Let'