Subscript is very common in a modern programming language. It seems to be a standard to use subscript to access some data structure like array and dictionary. In Swift, Array and Dictionary can be used with subscript as expected.

var arr = [1,2,3]
arr[2]            // 3
arr[2] = 4        // arr = [1,2,4]

var dic = ["cat":"meow", "goat":"mie"]
dic["cat"]          // {Some "meow"}
dic["cat"] = "miao" // dic = ["cat":"miao", "goat":"mie"]

Nothing special for array, but we should take more attention to dictionary. When we access a value of a dictionary with subscript, the result is an Optional value. This is easy to understand because you cannot limit a subscript of a dictionary. When trying to access an array with an exceeded index, there will be an exception. However, in dictionary it is very common that a key does not exist. In Swift, a nil is returned for this situation, which is regarded as a better way to handle it. So every time we use subscript to get a value from dictionary, we have to remember to get its real value with optional binding first.

As a modern language, Swift even allows us to customize subscript. It is for both classes: the classes we write ourselves, and the ones are already existing in the language (Yes I mean Array and Dictionary). In the standard library of Swift, you can find the subscript access methods are already supported for Array:

subscript (index: Int) -> T
subscript (subRange: Range<Int>) -> Slice<T>

There are two types of subscript access here, one accepts an Int for index and the other expects Range<Int> for a continuous range of indexes.

So here is the issue. How can we get several elements in a discrete collection of indexes? For example, what should we do if we want to know the value at index 0, 2 and 3 at the same time? There is no such subscript method to retrieve them at once now. We have to enumerate the indexes we want to know and get them from array one by one. It is not funny at all! There should be a way to do it easier. Adding a method for this purpose would be a great idea:

extension Array {
    subscript(input: [Int]) -> Slice<T> {
        get {
            var result = Slice<T>()
            for i in input {
                assert(i < self.count, "Index out of range")
                result.append(self[i])
            }
            return result
        }

        set {
            for (index,i) in enumerate(input) {
                assert(i < self.count, "Index out of range")
                self[i] = newValue[index]
            }
        }
    }
}

Cool, we can use Array in our way now:

var arr = [1,2,3,4,5]
arr[[0,2,3]]            //[1,3,4]
arr[[0,2,3]] = [-1,-3,-4]
arr                     //[-1,2,-3,-4,5]

Exercise

Although we implemented a subscript method with array as parameter here, it is far away from perfection. If you know something about variadic in Swift, you may wonder why we not use a more elegant way such as variadic here (just like the form of subscript(input: Int...)). Variadic is a better choice in every point except for demonstration purpose. If we use the form of subscript(input: Int...), there will be a conflicting with the built-in subscript (index: Int) version, which might cause this chapter too complicated. But in fact we can get a workaround by using subscript(first: Int, second: Int, others: Int...) instead, to clear up the ambiguity. You can try to implement this yourself.