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!