Why does the reverse() function in the Swift standard library return ReverseRandomAccessCollection?

Brynjar picture Brynjar · Jan 1, 2016 · Viewed 8.7k times · Source

Now that I've learned Swift (to a reasonable level) I'm trying to get to grips with the standard library, but in truth it's mainly ελληνικά to me!

So a specific question: I have an array of strings and I can call reverse() on it.

let arr = ["Mykonos", "Rhodes", "Naxos"].reverse()

Now naively I thought I'd get back a type of Array from this. (Ruby for example has a similar method that you pass an array and get back an array)

But arr is now actually of type

ReverseRandomAccessCollection<Array<String>>

which is actually a struct, which conforms to CollectionType:

public struct ReverseRandomAccessCollection<Base : CollectionType where Base.Index : RandomAccessIndexType> : _ReverseCollectionType

This means I can do this:

for item in arr {
  print(item)
}

but I can't do

print(arr[0])

Why is this designed to be this way?

Dictionaries in Swift also implement CollectionType, so I can do this:

let dict = ["greek" : "swift sometimes", "notgreek" : "ruby for this example"].reverse()

But dictionaries are not ordered like arrays, so why can I call reverse() on dicts?

Bonus points if anyone can point me in the direction of where I can read up and improve my Swift stdlib foo, Ευχαριστώ!

Answer

Martin R picture Martin R · Jan 1, 2016

It is an performance optimization for both time and memory. The ReverseRandomAccessCollection presents the elements of the original array in reverse order, without the need to create a new array and copying all elements (as long as the original array is not mutated).

You can access the reversed elements with subscripts:

let el0 = arr[arr.startIndex]
let el2 = arr[arr.startIndex.advancedBy(2)]

or

for i in arr.indices {
    print(arr[i])
}

You can also create an array explicitly with

let reversed = Array(["Mykonos", "Rhodes", "Naxos"].reversed())

A dictionary is also a sequence of Key/Value pairs. In

let dict = ["greek" : "swift sometimes", "notgreek" : "ruby for this example"].reverse()

a completely different reversed() method is called:

extension SequenceType {
    /// Return an `Array` containing the elements of `self` in reverse
    /// order.
    ///
    /// Complexity: O(N), where N is the length of `self`.
    @warn_unused_result
    public func reversed() -> [Self.Generator.Element]
}

The result is an array with the Key/Value pairs of the dictionary in reverse order. But this is of limited use because the order of the Key/Value pairs in a dictionary can be arbitrary.