Trying to add extension to StringProtocol

Hi All.

Having recently discovered StringProtocol, I decided to move my String extensions to StringProtocol, but I'm getting an error I don't understand. Hopefully I can get some help here.

Here is my old extension on String:

public extension String {
    public func split(pattern:String) -> [Substring] {
        var results = [Substring]()
        var remainingRange = self.startIndex..<self.endIndex
        while let matchRange = self.range(of:pattern, options:.regularExpression, range:remainingRange) {
            results.append(self[remainingRange.lowerBound..<matchRange.lowerBound])
            remainingRange = matchRange.upperBound..<self.endIndex
        }
        results.append(self[remainingRange])
        return results
    }
}

And here is the same thing added to StringProtocol:

public extension StringProtocol {
    public func split<T:StringProtocol>(pattern:T) -> [Self.SubSequence] {
        var results = [Self.SubSequence]()
        var remainingRange = self.startIndex..<self.endIndex
        while let matchRange = self.range(of:pattern, options:.regularExpression, range:remainingRange) {
            results.append(self[remainingRange.lowerBound..<matchRange.lowerBound])
            remainingRange = matchRange.upperBound..<self.endIndex
        }
        results.append(self[remainingRange])
        return results
    }
}

On the "while" line, I get this error:

'Self' requires the types 'Self.Index' and 'String.Index' be equivalent to use 'range'

I don't know how to address this. Can someone explain what this error means?

Thanks!

range(of:options:...) is constrained to where Index == String.Index, so it is not available to your method in all the cases your less‐constrained method aims for.

Add the same constraint your own extension (or just to the method) in order to use it. Then the availability will match and the method will compile:

extension StringProtocol where Index == String.Index {
    // ...
}

Hmm... There are a lot of things about this that I don't understand, but it works, so Thanks!

OK, I've just thought of a salient question to ask... The declaration of StringProtocol (swift/StringProtocol.swift at main ¡ apple/swift ¡ GitHub) already includes a "where Index == String.Index" clause, so why do I have to add it to the declaration of my extension?

2 Likes

That is a very good question. You forced me stop and think.

The answer is that the clause you noticed was added relatively recently, and is not part of any stable release yet. You’ll notice the documentation, which matches the 2.4.1 release, does not contain that clause.

So yes, once it is released, you will no longer need to specify the constraint yourself.

2 Likes

Yes, I added this to simply the very kind of code of @hexdreamer is trying to write. StringProtocol is only meant to be conformed to by stdlib types and String.Index was extended to support unimagined future flexibility here. We think it's sensible to require that potential future conformers (and there might not ever be any) use String.Index for their index type.

4 Likes