Background:
A subscript is a mechanism for accessing values inside collections, structures, and other types using square bracket syntax. It was added to Swift by analogy with other languages (for example, indexing in Python arrays, the [] operator in C++/Java) to make working with collections and similar objects more intuitive.
Issue:
Not all types support index access by default like arrays. When we have a structure or class with data, accessing elements often makes more sense to implement through familiar syntax (like myObject[index]), rather than through a method.
Solution:
Swift allows implementing a subscript for any custom type. It can be made read-only or read/write. Here’s an example of a structure implementing a subscript for working with a square matrix:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "Index out of range") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Index out of range") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
Key features:
subscript and can be either get-only or get/setCan subscripts only be used for collections?
No, subscripts can be implemented for any type: structure, class, enum. The data type inside does not need to be a collection; the main thing is the logic for handling requests through the subscript.
Can you have multiple subscripts with different signatures in one type?
Yes, it is allowed to overload the subscript with different parameter signatures:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
Is it allowed to use a subscript as a computed property without set?
Yes, a subscript can be read-only (get-only), then an attempt to write will cause a compilation error.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
In a large structure, a subscript is implemented without range checking, leading to application crashes on incorrect indices.
Pros:
Cons:
Matrix is implemented with a precondition on index ranges. Any error is caught immediately, not hitting production.
Pros:
Cons: