What is "subscript" in Swift
Though you may not feel it does, "subscript" plays important roles almost everywhere in Swift. Today, I will explain it.
Definition
The definition is very simple. Let's see some examples first:
let dictionary: [String, String] = ["example1": "foo",
"example2": "bar",
"example3": "buz"]
print(dictionary["example1"]) // output: foo
let string = "Hello, World"
let array: [Int] = [1, 1, 2, 3, 5, 8]
// get values
print(dictionary["example1"]) // output: foo
print(string[string.startIndex]) // output: H
print(array[4]) // output: 5
// set values
dictionary["example2"] = "some text"
string[string.startIndex] = "h"
array[0] = 0
When you manipulate dictionaries, arrays, and strings (that is, collections), you can retrieve or set the value like array["example1"]
. It is called "subscript". This feature is very simple and common in many other programming languages. Then, why does Swift call this simple functionality a "subscript"? That is because you can define subscript for types by yourself. Let's dive into how to define your custom subscript.
// these are all subscripts
someArray[index]
someDictionary[key]
How to define subscripts
Subscripts enable you to query instances of a type by writing one or more values in square brackets after the instance name just as collections do. Their syntax is very similar to method syntax and computed property syntax.
subscript(index: Int) -> Int {
get {
// return a subscript value here
}
set(valueName) {
// set a new subscript value
}
}
As shown in the example above, you can define custom subscripts with the subscript
keyword, one or more parameters, return type, and getter and setter. You can omit setter to make subscripts read-only. In addition, you can simplify the declaration of a read-only subscript without the get
keyword. Finally, you can do without (valueName)
; if it is not defined, the newValue
is used for specifying a new value as default.
// read-only subscript
subscript(index: Int) -> Int {
// return a subscript value here
}
// read-only subscript
subscript(index: Int) -> Int {
get {
// return a subscript value here
}
}
// without value name in setter
subscript(index: Int) -> Int {
get {
// return a subscript value here
}
set {
// set a new subscript value using "newValue"
}
}
Here is a full example of defining custom subscripts:
// read-only
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[1]) // output: 3
print(threeTimesTable[2]) // output: 6
print(threeTimesTable[3]) // output: 9
print(threeTimesTable[4]) // output: 12
print(threeTimesTable[5]) // output: 15
print(threeTimesTable[6]) // output: 18
class MyArray {
var internalArray: [Int] = []
subscript(index: Int) -> Int {
get {
return internalArray[index]
}
set {
internalArray[index] = newValue
}
}
}
let myArray = MyArray()
myArray.internalArray = [1, 2, 3, 4, 5]
// accessing a value calling getter of subscript
print(myArray[0]) // output: 1
print(myArray[2]) // output: 3
// set a value calling setter of subscript
myArray[1] = 10
print(myArray[1) // output: 10
In this way, you can retrieve and set property values in your custom types using the same syntax as collections.
Why and when subscripts should be used
Accessing elements in collections: Subscripts are commonly used with built-in types like arrays, dictionaries, and strings.
Custom types with index-based access: Subscripts are useful when you have a custom type that represents a collection or index-based data structure. They enable you to make your code expressive and easier to understand.