'adopting RandomAccessCollection protocol

public class Container2: RandomAccessCollection
{
    public typealias Indices = DefaultIndices<Container2>

    public typealias Index = Int
    //typealias SubSequence = Container2
    public var arr:[Int] = [1,2,3,4,5]
    
    public var endIndex: Index {
        return 5
    }
    
    public var startIndex:Index{
        return 0
    }
    
    public func index(after i: Int) -> Int{
        return i+1
    }
    
    public subscript(position: Int) -> Int{
        get{
            return arr[position]
        }
        set{
            arr[position] = newValue
        }
    }
    
    /*func index(before i: Int) -> Int{
        return i-1
    }*/
    
     public subscript(bounds: Range<Int>) -> Container2{
        get{
            return Container2()
        }
    }
}

I'm trying to adopt the RandomAccessCollection protocol from a class. I deliberately leave out the func index(before:) function because there is already a default implementation of that function in RandomAccessCollection. I do understand that that function's implementation is required because of BiDirectionalCollection from which RandomAccessCollection inherits. My question is why would the compiler complain that func index(before:) implementation is required when there is already a default implementation in RandomAccessCollection that i can use? Thanks.



Solution 1:[1]

why would the compiler complain that func index(before:) implementation is required when there is already a default implementation in RandomAccessCollection that i can use?

I had a similar problem as you and wondered the same. In the comments, Hamish answers our question, but I want to give more detail.

Read the main code comments to RandomAccessCollection.

/// The `RandomAccessCollection` protocol adds further constraints on the
/// associated `Indices` and `SubSequence` types, but otherwise imposes no
/// additional requirements over the `BidirectionalCollection` protocol.
/// However, in order to meet the complexity guarantees of a random-access
/// collection, either the index for your custom type must conform to the
/// `Strideable` protocol

You defined Indices as DefaultIndices<Container2>. This conflicts with typealias Index = Int because Int is a different type than Container2. The Indices element type has to be a collection of the Index type.

Another problem is that Container2 does not conform to Strideable like the code comment says. Because your index type of Container2 does not conform to Strideable then the protocol extensions for index(before:) on RandomAccessCollection cannot be used. Thus, the complier complains.

I copied your code into a playground, and made the complier error go away by changing 1 line:

    public typealias Indices = Range<Int>

Also, subscript(position:) makes sense but subscript(bounds:) is wrong. You have Container2 coded to return Int not copies of itself. You can delete that func because it is not needed.

The reason I hit a similar problem as you was because I tried to implement a type that conformed to RandomAccessCollection by using the errors that the Xcode code completion gave me. This is folly.

This question has a minimal conformance example. However, I pared that down to something even smaller.

struct SomeInts : RandomAccessCollection {
    var startIndex: Int { 0 }
    var endIndex: Int  { 5 }
    subscript(position: Int) -> Int {
        get { [51, 53, 59, 61, 67, 71][position] }
    }
} 

The lesson from this is: ignore Xcode code completion telling you to define those generic type aliases as concrete types. Instead, implement the minimum functions using concrete types, and let type inference tell the complier what those generic type aliases should be.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1