Manuel Manuel - 2 months ago 12
Swift Question

What is the `_base` property of an ReverseRandomAccessCollection?

Is it good practice to use the

_base
property to access the elements of a
ReverseRandomAccessCollection
?

let myArray = [1, 2, 3]
print(myArray.first) // returns 1

print(myArray.reversed().first) // returns 3
print(myArray.reversed()._base.first) // return 1, which is the underlying base array

Answer

A ReverseRandomAccessCollection (you can see its full implementation here) is a simply a wrapper that presents a reversed view onto an underlying RandomAccessCollection (this saves from having to do an O(n) walk through it).

The way this is achieved is through keeping an _base property of the underlying collection, and then implementing the RandomAccessCollection protocol in order to present a reversed view onto it, such reversing index traversal (comments mine):

public struct ReversedRandomAccessCollection<
  Base : RandomAccessCollection
> : RandomAccessCollection {

    public let _base: Base // the underlying collection to present the reversed view on

    // ...

    public var startIndex: Index { // startIndex accesses endIndex of _base
        return ReversedRandomAccessIndex(_base.endIndex)
    }

    public var endIndex: Index { // endIndex accesses startIndex of _base
        return ReversedRandomAccessIndex(_base.startIndex)
    }

    public func index(after i: Index) -> Index { // index(after:) gets the index(before:)
        return ReversedRandomAccessIndex(_base.index(before: i.base))
    }

    public func index(before i: Index) -> Index { // index(before:) gets the index(after:)
        return ReversedRandomAccessIndex(_base.index(after: i.base))
    }

    public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { 
        // index offset is simply made negative,
        // then forwarded to base's index(_:offsetBy:) method
        return ReversedRandomAccessIndex(_base.index(i.base, offsetBy: -n))
    }

    // ...
}

As the _base property is public, there's nothing to stop you from using it. However, underscore prefixed properties and methods are used to indicate implementation details that are not part of the public API – as they're often not designed to be used directly, and are subject to change without warning.

In this case you can simply work with the array before you call reversed() – it will be the same as _base (until you mutate it). Therefore, instead of doing:

myArray.reversed()._base.first

you should just do:

myArray.first

which will yield the same result.

Although, as others have said, your observation that myArray.reversed().first returns 1 and myArray.reversed()._base.first returns 3 (for an array of [1, 2, 3]) is incorrect – it's the other way around.

Comments