I'm writing some code that takes in a generic type, T that conforms to StringProtocol and returns a Substring and encountered some issues.
func foo<T>(_ str: T) -> Substring where T: StringProtocol {
return str.dropFirst()[...].prefix(20).dropLast(3).suffix(5)
}
For some reason, this code fails with the following compile-time error:
error: cannot convert return expression of type 'T.SubSequence' to return type 'Substring'
return str.dropFirst()[...].prefix(20).dropLast(3).suffix(5)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
as! Substring
This confused me because I thought that StringProtocol.SubSequence was just a type alias for Substring. Anyways, I thought "okay, let me check the definition of SubSequence on StringProtocol just to confirm my suspicions." Low and behold, I saw that in fact Substring is just the default value for StringProtocol.SubSequence and as such the two are not necessarily equal in a generic context. This surprised me, and I tried to think about why StringProtocol.SubSequence wouldn't just be a typealias for Substring because in practice, afaik, it always is, but to no avail. Then documentation I checked the documentation for StringProtocol and saw the following.
Do not declare new conformances to StringProtocol . Only the String and Substring types in the standard library are valid conforming types.
Since String.SubSequence is Substringand Substring.SubSequence is Substring, why would StringProtocol.SubSequence not just be equal to Substring? I literally cannot think of any reason/benefit for this. It seems to just be needlessly restrictive. Does anyone know why this is the case?
I noticed that changing the return type of foo to T.SubSequence fixes the problem above, but I also was a bit confused by that too. Shouldn't the return type be T.SubSequence.SubSequence.SubSequence.SubSequence.SubSequence instead? After some inspection, it seems that all of these operations return the SubSequence of the Collection they are called on. If this is the case and all of them produce the SubSequence of their input (even though in a non-generic context it is always Substring), why wouldn't the type be the longer aforementioned one? How does it know that all subsequent SubSequences of T are the same type? Can someone explain the black magic that is going on here?