Error occurs for example in Swift.org

When I try to use LazySplitCollection shown by Swift.org’s blog.(https://swift.org/blog/conditional-conformance/)

subscript(i: Index) -> Element {
        let separator = base[i...].index(where: isSeparator)
        return base[i..<(separator ?? endIndex)]
}

I can get a compiler error “Incorrect argument label in call (have ‘where:’, expected ‘after:’)” for base[i...].

I am really confused, to me this seems correct.

Also this is terrible that code in Swift org blog can’t compile.

Hi Yansong,

The blog post is about a new feature in Swift 4.1. Therefore, you’ll need Swift 4.1 to compile the example. The particular code you point out produces the error you see in Swift 4.0, but it compiles without error in Swift 4.1.

If you are using development toolchains with Xcode 9.2, be aware that Playgrounds continue to use the default toolchain; either compile a regular project or use Xcode 9.3 beta.

Thanks for reply.

struct LazySplitCollection<Base: Collection> {
    let base: Base
    let isSeparator: (Base.Element) -> Bool
}

extension LazySplitCollection: Collection  {
    typealias Element = Base.SubSequence
    typealias Index = Base.Index

    var startIndex: Index { return base.startIndex }
    var endIndex: Index { return base.endIndex }

    subscript(i: Index) -> Element {
        let separator = base.index(where: isSeparator)
        return base[i..<(separator ?? endIndex)]
    }

    func index(after i: Index) -> Index {
        let separator = base[i...].index(where: isSeparator)
        return separator.map(base.index(after:)) ?? endIndex
    }
}

For Swift 4.0

LazySplitCollection wants to confirm to Collection. It implements required ones so for others requirements it will use default implementation.

Particularly for SubSequence,
associatedtype SubSequence : Sequence = Slice<Self> where Self.Element == Self.SubSequence.Element, Self.SubSequence == Self.SubSequence.SubSequence

We will have a default SubSequence, which is a Slice<Self>.

For Slice itself, it is a collection. (https://developer.apple.com/documentation/swift/slice)

extension Collection where Self.SubSequence == Slice<Self> {
    public subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }
}

According to above, base[i…] should return a Slice, which is a collection.

In my opinion, base[i…].index(where:) should work.

Please correct me if I said something wrong.

The documentation you are viewing is for Swift 4.1, not for Swift 4.0. You can see the changes by choosing "API Changes: Show." Your reasoning is correct for Swift 4.1, and the code you're writing is correct for Swift 4.1.

In Swift 4.0, Collection.SubSequence is not constrained to conform to Collection.

You can make your code work in Swift 4.0 by adding “where Base.SubSequence : Collection” to the declaration of LazySplitCollection.

1 Like

Great! Thanks!

I see, thanks for Swift 4.0 correction!