Why Is the Shorthand Argument Name $0 Returning a Tuple of All Parameters

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



Leave a reply



Submit