Adding default values to subscript arguments in Swift 5.2
Published on: February 19, 2020The ability to define custom subscripts in Swift is really powerful. It allows us to write very natural and concise code. Consider the following example of a Grid
with a custom subscript:
struct Grid {
let items : [[GridItem]]
subscript(x x: Int, y y: Int) -> GridItem? {
guard !items.isEmpty, (items.startIndex...items.index(before: items.endIndex)).contains(x)
else { return nil }
let row = items[x]
guard !row.isEmpty, (row.startIndex...row.index(before: row.endIndex)).contains(y)
else { return nil }
return row[y]
}
}
Note that subscripts don't use labels by default. To make a subscript use labels, you need to manually declare the subscript label twice like I did in the code above (x x: Int
and y y: Int
). A subscript like the above would be used as follows:
let item = grid[x: 10, y: 2]
This example works fine in Swift 5.1 and earlier versions in Swift. New in Swift 5.2 is the ability to provide default values for subscript arguments:
struct Grid {
let items : [[GridItem]]
subscript(x x: Int = 0, y y: Int = 0) -> GridItem? {
guard !items.isEmpty, (items.startIndex...items.index(before: items.endIndex)).contains(x)
else { return nil }
let row = items[x]
guard !row.isEmpty, (row.startIndex...row.index(before: row.endIndex)).contains(y)
else { return nil }
return row[y]
}
}
This code is almost the same as the first example, except the subscript now has default arguments. This means that you can use the subscript as follows:
let item = grid[y: 2]
This will automatically call the subscript with a default value of 0
for the x
argument.
The fact that it wasn't possible to define default subscript arguments in Swift before was kind of a surprise for me to be honest, but I'm really happy that we have the possibility now. I think it will allow many people to write better subscripts for their objects.