I am trying to call the method .enumerate() on an instance of a type which conforms to the protocol Sequence. According to Apple's documentation, this should be correct, since .enumerate is part of the Sequence protocol.
However, I receive this complaint from the compiler:
Member 'enumerated' cannot be used on value of type 'any Sequence<URL>'; consider using a generic constraint instead.
Yet, if I remove the type annotation, then it works.
Here is an example which reproduces the problem:
func example() -> URL? {
let fm : FileManager = FileManager.default
let appDir : FileManager.SearchPathDirectory = FileManager.SearchPathDirectory.applicationDirectory
let domMask : FileManager.SearchPathDomainMask = FileManager.SearchPathDomainMask.allDomainsMask
let appResourceValues : [URLResourceKey] = [URLResourceKey.localizedNameKey]
var appURLs : any Sequence<URL> = fm.urls(for: appDir, in: domMask)
//var appURLs : Sequence<URL> = fm.urls(for: appDir, in: domMask)
//var appURLs = fm.urls(for: appDir, in: domMask)
var appURL : URL? = appURLs.enumerated().first { (offset: Int, element: URL) in
try! element.resourceValues(forKeys: Set(appResourceValues)).localizedName!.contains("App Store")
}?.element
return appURL
}
There are two commented lines in the code above, which are alternate ways to instantiate appURLs. If I use the first commented line, which is the old Swift syntax apparently, then I receive an error telling me that in order to add a type annotation which enforces a protocol, I need to use any protocolName, and not protocolName. (According to a comment on another post, this was a recent change in Swift: Use of protocol 'YourProtocol' as a type must be written 'any YourProtocol' Error, https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md)
If I use the second commented line, which removes the protocol annotation altogether, then the code works.
Is this a bug in Swift? How can I apply an annotation to indicate that it must conform to Sequence<URL> without breaking the code?
I tried to declare a generic type parameter, but Swift won't let me. None of these work:
associatedtype does exactly what I want: it creates a generic type parameter. But it doesn't work outside a protocol.








If you annotate
appURLswith the existential typeany Sequence<URL>, then that means that you don't know what concrete type it actually stores. This is problematic for callingenumerated, becauseenumeratedreturnsEnumeratedSequence<Self>:Selfmeans "type on which this is called" - the exact thing that you don't know. Sometimes, having an unknownSelfis fine. e.g. if methods with these signatures existed inSequence:All of these are covariant positions. It remains type safe to substitute
Selfin these positions withany Sequence<URL>, which is why you can still call these methods. However, it is not safe to do the same withEnumeratedSequence<Self>, because even thoughSomeConcreteImplementationOfSequenceis aany Sequence<URL>,EnumeratedSequence<SomeConcreteImplementationOfSequence>is not aEnumeratedSequence<any Sequence<URL>>. Generics are invariant in Swift - theSelfinEnumeratedSequence<Self>is in an invariant position.You can see they talk about when functions involving
Selfcan be called in this SE proposal:They even use
enumerated()as an example further down!Besides,
EnumeratedSequence<any Sequence<URL>>isn't even a valid type!EnumeratedSequencerequires its type parameter to be aSequence, butany Sequence<URL>isn't one! BecauseSequencehas static requirements.Responding to your comments,
That is not bad practice. Rather, putting type annotations where they are not needed is considered not Swifty.
In that case, your function can return an
AnySequence<URL>. Unlikeany Sequence<URL>, this is a concrete type. You just need to do the extra step of wrapping other sequence types to it: