I've been spending some time with Swift's opaque types trying to understand some of their nuances and I am running into some issues. I've narrowed down my issue to a very simple, albeit contrived, example.
I've defined a protocol ContentFetcher with a function fetch(). I also have a struct VideoFetcher that conforms to this protocol. Here's the code for these:
protocol ContentFetcher: Equatable {
func fetch() -> Int
}
struct VideoFetcher: ContentFetcher {
func fetch() -> Int {
1
}
}
I've then created a FetcherFactory struct that has a static function getFetcher() which returns some ContentFetcher:
struct FetcherFactory {
static func getFetcher() -> some ContentFetcher {
return VideoFetcher()
}
}
However, when I try to create instances of ContentFetcher and compare them, I'm receiving compiler errors. Here's the code and the errors:
struct S {
let fetcher1: some ContentFetcher = FetcherFactory.getFetcher()
let fetcher2: some ContentFetcher = FetcherFactory.getFetcher()
func start() {
let fetcher3 = FetcherFactory.getFetcher()
let fetcher4 = FetcherFactory.getFetcher()
// Success: prints 'true'
print(fetcher3 == fetcher4)
// Error: Cannot convert value of type 'some ContentFetcher' (type of 'S.fetcher2')
// to expected argument type 'some ContentFetcher' (type of 'S.fetcher1')
print(fetcher1 == fetcher2)
let fetcher5: some ContentFetcher = FetcherFactory.getFetcher()
let fetcher6: some ContentFetcher = FetcherFactory.getFetcher()
// Error: Cannot convert value of type 'some ContentFetcher' (type of 'fetcher6')
// to expected argument type 'some ContentFetcher' (type of 'fetcher5')
print(fetcher5 == fetcher6)
}
}
S().start()
I understand that the opaque type returned by static func getFetcher() -> some ContentFetcher is used to hide the exact type of the return value. However, I cannot explain why fetcher3 == fetcher4 compiles successfully when both fetcher1 == fetcher2 and fetcher5 == fetcher6 generate errors. It seems that when I let the compiler infer the opaque return type for fetcher3 and fetcher4 that the type identity is preserved and the compiler knows both types are the same. But if I make the opaque types explicit (let fetcher1: some ContentFetcher ...) then this identity is lost. Why is this when the return type of the getFetcher() method is still some ContentFetcher?
Also, I believe I must specify the type for stored properties; I get a compiler error if I remove some ContentFetcher from the type annotation of fetcher1 and fetcher2 (Error: Property definition has inferred type 'some ContentFetcher', involving the 'some' return type of another declaration). Why is this?
Any help would be much appreciated. Thanks!