What does $0 and $1 mean in Swift Closures?
Solution 1
$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
}
Solution 2
TL;DR
Swift 5.5
$0
and$1
are Closure’s first and second shorthand arguments (a.k.a.Shorthand Argument Names
orSAN
for short). The shorthand argument names are automatically provided by Swift. The first argument can be referenced by$0
, the second argument can be referenced by$1
, the third one by$2
, and so on.
As you know, a Closure is a self-contained block of functionality (a function without name) that can be passed around and used in your code. Closure has different names in other programming languages as well as slight differences in meaning – it's Lambda in Python and Kotlin, or Block in C and Obj-C.
Shortening a Closure
let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]
1. Normal Function
func backward(_ n1: String, _ n2: String) -> Bool {
return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)
/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */
2. Inline Closure Expression
reverseOrder = coffee.sorted(by: { (n1: String,
n2: String) -> Bool in return n1 > n2 } )
3. Inferring Type From Context
reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )
4. Implicit Returns from Single-Expression Closures
reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )
5. Shorthand Argument Names
reverseOrder = coffee.sorted(by: { $0 > $1 } )
/* $0 and $1 are closure’s first and second String arguments. */
6. Operator Methods
reverseOrder = coffee.sorted(by: >)
/* RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"] */
Higher Order Function map
with dot notation
let companies = ["bmw", "kfc", "ibm", "htc"]
let uppercased = companies.map { (item) -> String in item.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
Shorthand Argument Name in HOF map
let uppercased = companies.map { $0.uppercased() }
/* RESULT: ["BMW", "KFC", "IBM", "HTC"] */
SAN in HOF filter
with remainder operator
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let filteredNumbers = numbers.filter { ($0 % 2) == 0 }
print(filteredNumbers)
/* RESULT: [2, 4, 6, 8, 10] */
SAN in Variadic functions
Variadic functions are ones that accept any number of parameters. Shorthand Argument Names are perfect for such cases.
fileprivate func dessert(_ fruits: String...) -> Bool {
return fruits.contains { $0 == "Apple" }
}
let contains = dessert("Mango", "Durian", "apple")
print(contains)
/* RESULT: false */
Repeating $0
let cubedNumber = { $0 * $0 * $0 } (25)
print(cubedNumber)
/* RESULT: 25^3 = 15625 */
Three Shorthand Argument Names – $0
, $1
, $2
let math: (Int8, Int8, Int8) -> Int8 = { $0 + $1 - $2 }
func feedClosure() -> (Int8, Int8, Int8) -> Int8 {
return math
}
feedClosure()(10, 20, 100)
/* RESULT: (10 + 20 - 100) = -70 */
Five SANs – $0
, $1
, $2
, $3
, $4
let factorial = { $0 * $1 * $2 * $3 * $4 } (1, 2, 3, 4, 5)
print(factorial)
/* RESULT: 5! = 120 */
Key Path Expression
In Swift 5.2 you can access parameters of every instance via key path expression:
struct Lighter {
let manufacturer: String
let refillable: Bool
}
let zippo = Lighter(manufacturer: "Zippo", refillable: true)
let cricket = Lighter(manufacturer: "Cricket", refillable: false)
let lighters: [Lighter] = [zippo, cricket]
let refillableOnes = lighters.map(\.refillable)
print(refillableOnes)
/* RESULT: [true, false] */
Of course, you can alternatively use a familiar syntax:
Regular syntax – $0.property
:
let refillableOnes = lighters.map { $0.refillable }
print(refillableOnes)
/* RESULT: [true, false] */
Shorthand Argument Name with a subscript
let arrays: [[String]] = [["Hello", "Hola"], ["world", "mundo"]]
let helloWorld = arrays.compactMap { $0[0] }
print(helloWorld)
/* RESULT: ["Hello", "world"] */
One more example with a subscript:
let dictionaries: [[Int8: Any?]] = [[1: "x"], [2: nil], [3: "z"]]
let values = dictionaries.compactMap { $0[$0.startIndex].value }
print(values)
/* RESULT: ["x", "z"] */
Or look at this example:
let sett: Set<String> = ["One", "", "Three"]
sett.map {
switch $0.isEmpty {
case true:
print("Empty")
case false:
print("Element \($0) isn't empty")
}
}
/* RESULT: "Element Three isn't empty" */
/* "Empty" */
/* "Element One isn't empty" */
Shorthand Argument Name in Completion Handler
let completionHandler: ((Bool) -> Void)? = {
if $0 {
print("It is true, sister...")
} else {
print("False")
}
}
completionHandler?(true)
/* RESULT: It is true, sister... */
Regular syntax, however, is as following:
let completionHandler: ((Bool) -> Void)? = { sayTheTruth in
if sayTheTruth {
print("It is true, sister...")
} else {
print("False")
}
}
completionHandler?(false)
/* RESULT: False */
SAN in ForEach structure in SwiftUI
let columns: [GridItem] = Array(repeating: .init(.fixed(70)), count: 5)
var body: some View {
ScrollView {
LazyVGrid(columns: columns) {
ForEach((1...10), id: \.self) {
Text("\($0)").frame(maxWidth: .infinity)
}
}
}
}
/* RESULT: 1 2 3 4 5 */
/* 6 7 8 9 10 */
Operator Method vs SAN
Operator Method:
let records: [Int] = [110, 108, 107, 109, 108]
public func averageSpeed(records: [Int]) throws -> Int {
let average = records.reduce(0, +) / records.count
return average
}
try averageSpeed(records: records)
/* RESULT: 108 */
Shorthand Argument Names $0 and $1:
public func averageSpeed(records: [Int]) throws -> Int {
let average = records.reduce(0) { $0 + $1 } / records.count
return average
}
try averageSpeed(records: records)
/* RESULT: 108 */
Swift vs Kotlin vs Python
Also, let's see how Kotlin's lambda is similar to Swift's closure:
Swift
let element: [String] = ["Argentum","Aurum","Platinum"]
let characterCount = element.map { $0.count }
print(characterCount)
/* RESULT: [8, 5, 8] */
Kotlin
Often Kotlin's lambda expression has only one parameter with implicit name: it
.
val element = listOf("Argentum","Aurum","Platinum")
val characterCount = element.map { it.length }
println(characterCount)
/* RESULT: [8, 5, 8] */
But in Python there's no equivalent of Shorthand Argument Name
.
Python
element = ["Argentum","Aurum","Platinum"]
characterCount = list(map(lambda x: len(x), element))
print(characterCount)
# RESULT: [8, 5, 8]
Solution 3
It represents shorthanded arguments sent into a closure, this example breaks it down:
Swift 4:
var add = { (arg1: Int, arg2: Int) -> Int in
return arg1 + arg2
}
add = { (arg1, arg2) -> Int in
return arg1 + arg2
}
add = { arg1, arg2 in
arg1 + arg2
}
add = {
$0 + $1
}
let result = add(20, 20) // 40
Solution 4
The refer to the first and second arguments of sort. Here, sort
compares 2 elements and order them.
You can look up Swift official documentation for more info:
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
Solution 5
In Addition with @Bobby's Answer I would like to Add an Example
var add: (Int,Int,Int)->Int
add = {
//So here the $0 is first argument $1 is second argument $3 is third argument
return $0 + $1 + $2
//The above statement can also be written as $0 + $1 + $2 i.e is return is optional
}
let result = add(20, 30, 40)
print(result) // Prints 90
aashish tamsya
I’m a mobile developer and designer with 4+ years of experience in both iOS and Android application development. I have worked on enterprise and integrated apps for major clients such as Shell, GEHC, HealthKart, SANOFI, and ICICI. Until recently, I led the mobile team for Effective Digital, a software engineer focused on creating robust and scalable applications. In this role, I was focused on architecture design, setting up unit testing, initiating test-driven development and all processes for continuous integration and deployment, although I have done extensive open source work in the past. Successes included creating an application for mass companies and customer with the real-time campaign that generated enormous user activity and was key to the successful launch of the GreenOrbit iOS application on App Store in 2019. Previous experience includes working with product-based organizations and service companies. Colleagues know me as a highly creative engineer who can always be trusted to come up with quality and performance over the application. But I know that the client’s business comes first, and I never try to impose my ideas on others. Instead, I spend a lot of time understanding the business and the audience before suggesting ideas. I can (and often do) work well alone, but I’m at my best collaborating with others. I'm obsessed about quality and performance above everything else. I can own and deliver projects as an Individual Contributor and as a Team Member. I have been participating in all phases of the product development lifecycle (Requirements, Design, Coding, Testing, and Release) following a structured engineering process to ensure quality and reliability. I have a degree in Bachelor of Engineering from the University of Pune. I’m currently freelancing while I pursue new opportunities, I like to keep learning new things and can be reached either through this profile or by visiting my website, my personal apps.
Updated on August 08, 2021Comments
-
aashish tamsya almost 3 years
let sortedNumbers = numbers.sort { $0 > $1 } print(sortedNumbers)
Can anyone explain, what
$0
and$1
means in swift?More Sample
array.forEach { actions.append($0) }